From 6bac5d59990d5c2917827d89df15b43539b8f718 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Mon, 14 Apr 2025 04:28:43 +0100 Subject: [PATCH 001/158] gh actions --- .github/workflows/tests.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..e62030a --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,28 @@ +name: Playwright Tests for WordPress +on: + push: + pull_request: + +jobs: + playwright-tests: + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 18 + + - name: Install Dependencies + run: npm install + + - name: Install Playwright Browsers + run: npx playwright install --with-deps + + # - name: Run Playwright Tests + # env: + # BASE_URL: https://your-wordpress-site.com + # run: npx playwright test From 6a7bebba92e0534ebb5d9293fe7fe34559611ccd Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Mon, 14 Apr 2025 04:30:36 +0100 Subject: [PATCH 002/158] gh --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e62030a..fbde987 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,7 +14,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 22 - name: Install Dependencies run: npm install From 232f8a8b5cc8a6ec21c793334b677e7ad06b77fe Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Mon, 5 May 2025 07:58:26 +0100 Subject: [PATCH 003/158] Tests --- .github/workflows/tests.yml | 118 ++++++-- .gitignore | 7 + package.json | 20 +- playwright.config.ts | 79 +++++ pnpm-lock.yaml | 53 ++++ tests-examples/demo-todo-app.spec.ts | 437 +++++++++++++++++++++++++++ tests/example.spec.ts | 18 ++ 7 files changed, 703 insertions(+), 29 deletions(-) create mode 100644 playwright.config.ts create mode 100644 tests-examples/demo-todo-app.spec.ts create mode 100644 tests/example.spec.ts diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fbde987..5521f45 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,28 +1,106 @@ -name: Playwright Tests for WordPress +name: E2E Tests + on: - push: - pull_request: + push: + pull_request: jobs: - playwright-tests: - runs-on: ubuntu-latest + e2e: + runs-on: ubuntu-latest + services: + mysql: + image: mysql:8.0 + env: + MYSQL_DATABASE: wordpress + MYSQL_ROOT_PASSWORD: root + ports: [ 3306:3306 ] + options: >- + --health-cmd="mysqladmin ping -h 127.0.0.1 -uroot -proot" + --health-interval=10s + --health-timeout=5s + --health-retries=5 + + env: + WP_VERSION: 6.5.3 + WP_SITE_URL: http://localhost:8888 + WP_DB_NAME: wordpress + WP_DB_USER: root + WP_DB_PASS: root + WP_DB_HOST: 127.0.0.1 + + steps: + - name: Checkout plugin + uses: actions/checkout@v4 + + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 8.2 + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y unzip curl jq + + - name: Cache WordPress archive + id: cache-wordpress + uses: actions/cache@v3 + with: + path: wordpress + key: wp-${{ env.WP_VERSION }} + + - name: Download WordPress + if: steps.cache-wordpress.outputs.cache-hit != 'true' + run: | + curl -O https://wordpress.org/wordpress-${WP_VERSION}.tar.gz + tar -xzf wordpress-${WP_VERSION}.tar.gz + rm wordpress-${WP_VERSION}.tar.gz + + - name: Configure WordPress + run: | + cp wordpress/wp-config-sample.php wordpress/wp-config.php + sed -i "s/database_name_here/${WP_DB_NAME}/" wordpress/wp-config.php + sed -i "s/username_here/${WP_DB_USER}/" wordpress/wp-config.php + sed -i "s/password_here/${WP_DB_PASS}/" wordpress/wp-config.php + echo "define( 'DB_HOST', '${WP_DB_HOST}' );" >> wordpress/wp-config.php + echo "define( 'WP_HOME', '${WP_SITE_URL}' );" >> wordpress/wp-config.php + echo "define( 'WP_SITEURL', '${WP_SITE_URL}' );" >> wordpress/wp-config.php + + - name: Install WordPress + run: | + curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar + chmod +x wp-cli.phar + sudo mv wp-cli.phar /usr/local/bin/wp + wp core install \ + --url="${WP_SITE_URL}" \ + --title="Test Site" \ + --admin_user=admin \ + --admin_password=admin \ + --admin_email=test@example.com \ + --path=wordpress \ + --skip-email \ + --allow-root - steps: - - name: Checkout Repository - uses: actions/checkout@v4 + - name: Install plugin + run: | + PLUGIN_SLUG=$(basename "$GITHUB_WORKSPACE") + ln -s "$GITHUB_WORKSPACE" "wordpress/wp-content/plugins/simpleanalytics" + wp plugin activate simpleanalytics --path=wordpress --allow-root - - name: Set up Node.js - uses: actions/setup-node@v4 - with: - node-version: 22 + - name: Start PHP server + run: | + php -S localhost:8888 -t wordpress > /dev/null 2>&1 & + sleep 5 - - name: Install Dependencies - run: npm install + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 - - name: Install Playwright Browsers - run: npx playwright install --with-deps + - name: Install Playwright and dependencies + run: | + npm ci + npx playwright install --with-deps - # - name: Run Playwright Tests - # env: - # BASE_URL: https://your-wordpress-site.com - # run: npx playwright test + - name: Run Playwright tests + run: npx playwright test diff --git a/.gitignore b/.gitignore index cedebe2..32e9c6c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,10 @@ node* vendor* build + +# Playwright +node_modules/ +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/package.json b/package.json index 595a1ae..64c348d 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,13 @@ { - "private": true, - "scripts": { - "dev": "tailwindcss -i resources/css/settings.css -o build/css/settings.css --watch", - "build": "tailwindcss build -i resources/css/settings.css -o build/css/settings.css" - }, - "devDependencies": { - "@tailwindcss/forms": "^0.5.8", - "tailwindcss": "^3.4.10" - } + "private": true, + "scripts": { + "dev": "tailwindcss -i resources/css/settings.css -o build/css/settings.css --watch", + "build": "tailwindcss build -i resources/css/settings.css -o build/css/settings.css" + }, + "devDependencies": { + "@playwright/test": "^1.52.0", + "@tailwindcss/forms": "^0.5.8", + "@types/node": "^22.15.3", + "tailwindcss": "^3.4.10" + } } diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..a05d8b5 --- /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/pnpm-lock.yaml b/pnpm-lock.yaml index fa86b90..0113137 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,9 +8,15 @@ importers: .: devDependencies: + '@playwright/test': + specifier: ^1.52.0 + version: 1.52.0 '@tailwindcss/forms': specifier: ^0.5.8 version: 0.5.8(tailwindcss@3.4.10) + '@types/node': + specifier: ^22.15.3 + version: 22.15.3 tailwindcss: specifier: ^3.4.10 version: 3.4.10 @@ -59,11 +65,19 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@playwright/test@1.52.0': + resolution: {integrity: sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==} + engines: {node: '>=18'} + hasBin: true + '@tailwindcss/forms@0.5.8': resolution: {integrity: sha512-DJs7B7NPD0JH7BVvdHWNviWmunlFhuEkz7FyFxE4japOWYMLl9b1D6+Z9mivJJPWr6AEbmlPqgiFRyLwFB1SgQ==} peerDependencies: tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20' + '@types/node@22.15.3': + resolution: {integrity: sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -162,6 +176,11 @@ packages: resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -303,6 +322,16 @@ packages: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} + playwright-core@1.52.0: + resolution: {integrity: sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.52.0: + resolution: {integrity: sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==} + engines: {node: '>=18'} + hasBin: true + postcss-import@15.1.0: resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} engines: {node: '>=14.0.0'} @@ -425,6 +454,9 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -491,11 +523,19 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true + '@playwright/test@1.52.0': + dependencies: + playwright: 1.52.0 + '@tailwindcss/forms@0.5.8(tailwindcss@3.4.10)': dependencies: mini-svg-data-uri: 1.4.4 tailwindcss: 3.4.10 + '@types/node@22.15.3': + dependencies: + undici-types: 6.21.0 + ansi-regex@5.0.1: {} ansi-regex@6.0.1: {} @@ -588,6 +628,9 @@ snapshots: cross-spawn: 7.0.3 signal-exit: 4.1.0 + fsevents@2.3.2: + optional: true + fsevents@2.3.3: optional: true @@ -698,6 +741,14 @@ snapshots: pirates@4.0.6: {} + playwright-core@1.52.0: {} + + playwright@1.52.0: + dependencies: + playwright-core: 1.52.0 + optionalDependencies: + fsevents: 2.3.2 + postcss-import@15.1.0(postcss@8.4.44): dependencies: postcss: 8.4.44 @@ -840,6 +891,8 @@ snapshots: ts-interface-checker@0.1.13: {} + undici-types@6.21.0: {} + util-deprecate@1.0.2: {} which@2.0.2: diff --git a/tests-examples/demo-todo-app.spec.ts b/tests-examples/demo-todo-app.spec.ts new file mode 100644 index 0000000..8641cb5 --- /dev/null +++ b/tests-examples/demo-todo-app.spec.ts @@ -0,0 +1,437 @@ +import { test, expect, type Page } from '@playwright/test'; + +test.beforeEach(async ({ page }) => { + await page.goto('https://demo.playwright.dev/todomvc'); +}); + +const TODO_ITEMS = [ + 'buy some cheese', + 'feed the cat', + 'book a doctors appointment' +] as const; + +test.describe('New Todo', () => { + test('should allow me to add todo items', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + // Create 1st todo. + await newTodo.fill(TODO_ITEMS[0]); + await newTodo.press('Enter'); + + // Make sure the list only has one todo item. + await expect(page.getByTestId('todo-title')).toHaveText([ + TODO_ITEMS[0] + ]); + + // Create 2nd todo. + await newTodo.fill(TODO_ITEMS[1]); + await newTodo.press('Enter'); + + // Make sure the list now has two todo items. + await expect(page.getByTestId('todo-title')).toHaveText([ + TODO_ITEMS[0], + TODO_ITEMS[1] + ]); + + await checkNumberOfTodosInLocalStorage(page, 2); + }); + + test('should clear text input field when an item is added', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + // Create one todo item. + await newTodo.fill(TODO_ITEMS[0]); + await newTodo.press('Enter'); + + // Check that input is empty. + await expect(newTodo).toBeEmpty(); + await checkNumberOfTodosInLocalStorage(page, 1); + }); + + test('should append new items to the bottom of the list', async ({ page }) => { + // Create 3 items. + await createDefaultTodos(page); + + // create a todo count locator + const todoCount = page.getByTestId('todo-count') + + // Check test using different methods. + await expect(page.getByText('3 items left')).toBeVisible(); + await expect(todoCount).toHaveText('3 items left'); + await expect(todoCount).toContainText('3'); + await expect(todoCount).toHaveText(/3/); + + // Check all items in one call. + await expect(page.getByTestId('todo-title')).toHaveText(TODO_ITEMS); + await checkNumberOfTodosInLocalStorage(page, 3); + }); +}); + +test.describe('Mark all as completed', () => { + test.beforeEach(async ({ page }) => { + await createDefaultTodos(page); + await checkNumberOfTodosInLocalStorage(page, 3); + }); + + test.afterEach(async ({ page }) => { + await checkNumberOfTodosInLocalStorage(page, 3); + }); + + test('should allow me to mark all items as completed', async ({ page }) => { + // Complete all todos. + await page.getByLabel('Mark all as complete').check(); + + // Ensure all todos have 'completed' class. + await expect(page.getByTestId('todo-item')).toHaveClass(['completed', 'completed', 'completed']); + await checkNumberOfCompletedTodosInLocalStorage(page, 3); + }); + + test('should allow me to clear the complete state of all items', async ({ page }) => { + const toggleAll = page.getByLabel('Mark all as complete'); + // Check and then immediately uncheck. + await toggleAll.check(); + await toggleAll.uncheck(); + + // Should be no completed classes. + await expect(page.getByTestId('todo-item')).toHaveClass(['', '', '']); + }); + + test('complete all checkbox should update state when items are completed / cleared', async ({ page }) => { + const toggleAll = page.getByLabel('Mark all as complete'); + await toggleAll.check(); + await expect(toggleAll).toBeChecked(); + await checkNumberOfCompletedTodosInLocalStorage(page, 3); + + // Uncheck first todo. + const firstTodo = page.getByTestId('todo-item').nth(0); + await firstTodo.getByRole('checkbox').uncheck(); + + // Reuse toggleAll locator and make sure its not checked. + await expect(toggleAll).not.toBeChecked(); + + await firstTodo.getByRole('checkbox').check(); + await checkNumberOfCompletedTodosInLocalStorage(page, 3); + + // Assert the toggle all is checked again. + await expect(toggleAll).toBeChecked(); + }); +}); + +test.describe('Item', () => { + + test('should allow me to mark items as complete', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + // Create two items. + for (const item of TODO_ITEMS.slice(0, 2)) { + await newTodo.fill(item); + await newTodo.press('Enter'); + } + + // Check first item. + const firstTodo = page.getByTestId('todo-item').nth(0); + await firstTodo.getByRole('checkbox').check(); + await expect(firstTodo).toHaveClass('completed'); + + // Check second item. + const secondTodo = page.getByTestId('todo-item').nth(1); + await expect(secondTodo).not.toHaveClass('completed'); + await secondTodo.getByRole('checkbox').check(); + + // Assert completed class. + await expect(firstTodo).toHaveClass('completed'); + await expect(secondTodo).toHaveClass('completed'); + }); + + test('should allow me to un-mark items as complete', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + // Create two items. + for (const item of TODO_ITEMS.slice(0, 2)) { + await newTodo.fill(item); + await newTodo.press('Enter'); + } + + const firstTodo = page.getByTestId('todo-item').nth(0); + const secondTodo = page.getByTestId('todo-item').nth(1); + const firstTodoCheckbox = firstTodo.getByRole('checkbox'); + + await firstTodoCheckbox.check(); + await expect(firstTodo).toHaveClass('completed'); + await expect(secondTodo).not.toHaveClass('completed'); + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + + await firstTodoCheckbox.uncheck(); + await expect(firstTodo).not.toHaveClass('completed'); + await expect(secondTodo).not.toHaveClass('completed'); + await checkNumberOfCompletedTodosInLocalStorage(page, 0); + }); + + test('should allow me to edit an item', async ({ page }) => { + await createDefaultTodos(page); + + const todoItems = page.getByTestId('todo-item'); + const secondTodo = todoItems.nth(1); + await secondTodo.dblclick(); + await expect(secondTodo.getByRole('textbox', { name: 'Edit' })).toHaveValue(TODO_ITEMS[1]); + await secondTodo.getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); + await secondTodo.getByRole('textbox', { name: 'Edit' }).press('Enter'); + + // Explicitly assert the new text value. + await expect(todoItems).toHaveText([ + TODO_ITEMS[0], + 'buy some sausages', + TODO_ITEMS[2] + ]); + await checkTodosInLocalStorage(page, 'buy some sausages'); + }); +}); + +test.describe('Editing', () => { + test.beforeEach(async ({ page }) => { + await createDefaultTodos(page); + await checkNumberOfTodosInLocalStorage(page, 3); + }); + + test('should hide other controls when editing', async ({ page }) => { + const todoItem = page.getByTestId('todo-item').nth(1); + await todoItem.dblclick(); + await expect(todoItem.getByRole('checkbox')).not.toBeVisible(); + await expect(todoItem.locator('label', { + hasText: TODO_ITEMS[1], + })).not.toBeVisible(); + await checkNumberOfTodosInLocalStorage(page, 3); + }); + + test('should save edits on blur', async ({ page }) => { + const todoItems = page.getByTestId('todo-item'); + await todoItems.nth(1).dblclick(); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).dispatchEvent('blur'); + + await expect(todoItems).toHaveText([ + TODO_ITEMS[0], + 'buy some sausages', + TODO_ITEMS[2], + ]); + await checkTodosInLocalStorage(page, 'buy some sausages'); + }); + + test('should trim entered text', async ({ page }) => { + const todoItems = page.getByTestId('todo-item'); + await todoItems.nth(1).dblclick(); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill(' buy some sausages '); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Enter'); + + await expect(todoItems).toHaveText([ + TODO_ITEMS[0], + 'buy some sausages', + TODO_ITEMS[2], + ]); + await checkTodosInLocalStorage(page, 'buy some sausages'); + }); + + test('should remove the item if an empty text string was entered', async ({ page }) => { + const todoItems = page.getByTestId('todo-item'); + await todoItems.nth(1).dblclick(); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill(''); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Enter'); + + await expect(todoItems).toHaveText([ + TODO_ITEMS[0], + TODO_ITEMS[2], + ]); + }); + + test('should cancel edits on escape', async ({ page }) => { + const todoItems = page.getByTestId('todo-item'); + await todoItems.nth(1).dblclick(); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); + await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Escape'); + await expect(todoItems).toHaveText(TODO_ITEMS); + }); +}); + +test.describe('Counter', () => { + test('should display the current number of todo items', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + // create a todo count locator + const todoCount = page.getByTestId('todo-count') + + await newTodo.fill(TODO_ITEMS[0]); + await newTodo.press('Enter'); + + await expect(todoCount).toContainText('1'); + + await newTodo.fill(TODO_ITEMS[1]); + await newTodo.press('Enter'); + await expect(todoCount).toContainText('2'); + + await checkNumberOfTodosInLocalStorage(page, 2); + }); +}); + +test.describe('Clear completed button', () => { + test.beforeEach(async ({ page }) => { + await createDefaultTodos(page); + }); + + test('should display the correct text', async ({ page }) => { + await page.locator('.todo-list li .toggle').first().check(); + await expect(page.getByRole('button', { name: 'Clear completed' })).toBeVisible(); + }); + + test('should remove completed items when clicked', async ({ page }) => { + const todoItems = page.getByTestId('todo-item'); + await todoItems.nth(1).getByRole('checkbox').check(); + await page.getByRole('button', { name: 'Clear completed' }).click(); + await expect(todoItems).toHaveCount(2); + await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]); + }); + + test('should be hidden when there are no items that are completed', async ({ page }) => { + await page.locator('.todo-list li .toggle').first().check(); + await page.getByRole('button', { name: 'Clear completed' }).click(); + await expect(page.getByRole('button', { name: 'Clear completed' })).toBeHidden(); + }); +}); + +test.describe('Persistence', () => { + test('should persist its data', async ({ page }) => { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + for (const item of TODO_ITEMS.slice(0, 2)) { + await newTodo.fill(item); + await newTodo.press('Enter'); + } + + const todoItems = page.getByTestId('todo-item'); + const firstTodoCheck = todoItems.nth(0).getByRole('checkbox'); + await firstTodoCheck.check(); + await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]); + await expect(firstTodoCheck).toBeChecked(); + await expect(todoItems).toHaveClass(['completed', '']); + + // Ensure there is 1 completed item. + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + + // Now reload. + await page.reload(); + await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]); + await expect(firstTodoCheck).toBeChecked(); + await expect(todoItems).toHaveClass(['completed', '']); + }); +}); + +test.describe('Routing', () => { + test.beforeEach(async ({ page }) => { + await createDefaultTodos(page); + // make sure the app had a chance to save updated todos in storage + // before navigating to a new view, otherwise the items can get lost :( + // in some frameworks like Durandal + await checkTodosInLocalStorage(page, TODO_ITEMS[0]); + }); + + test('should allow me to display active items', async ({ page }) => { + const todoItem = page.getByTestId('todo-item'); + await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); + + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + await page.getByRole('link', { name: 'Active' }).click(); + await expect(todoItem).toHaveCount(2); + await expect(todoItem).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]); + }); + + test('should respect the back button', async ({ page }) => { + const todoItem = page.getByTestId('todo-item'); + await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); + + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + + await test.step('Showing all items', async () => { + await page.getByRole('link', { name: 'All' }).click(); + await expect(todoItem).toHaveCount(3); + }); + + await test.step('Showing active items', async () => { + await page.getByRole('link', { name: 'Active' }).click(); + }); + + await test.step('Showing completed items', async () => { + await page.getByRole('link', { name: 'Completed' }).click(); + }); + + await expect(todoItem).toHaveCount(1); + await page.goBack(); + await expect(todoItem).toHaveCount(2); + await page.goBack(); + await expect(todoItem).toHaveCount(3); + }); + + test('should allow me to display completed items', async ({ page }) => { + await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + await page.getByRole('link', { name: 'Completed' }).click(); + await expect(page.getByTestId('todo-item')).toHaveCount(1); + }); + + test('should allow me to display all items', async ({ page }) => { + await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); + await checkNumberOfCompletedTodosInLocalStorage(page, 1); + await page.getByRole('link', { name: 'Active' }).click(); + await page.getByRole('link', { name: 'Completed' }).click(); + await page.getByRole('link', { name: 'All' }).click(); + await expect(page.getByTestId('todo-item')).toHaveCount(3); + }); + + test('should highlight the currently applied filter', async ({ page }) => { + await expect(page.getByRole('link', { name: 'All' })).toHaveClass('selected'); + + //create locators for active and completed links + const activeLink = page.getByRole('link', { name: 'Active' }); + const completedLink = page.getByRole('link', { name: 'Completed' }); + await activeLink.click(); + + // Page change - active items. + await expect(activeLink).toHaveClass('selected'); + await completedLink.click(); + + // Page change - completed items. + await expect(completedLink).toHaveClass('selected'); + }); +}); + +async function createDefaultTodos(page: Page) { + // create a new todo locator + const newTodo = page.getByPlaceholder('What needs to be done?'); + + for (const item of TODO_ITEMS) { + await newTodo.fill(item); + await newTodo.press('Enter'); + } +} + +async function checkNumberOfTodosInLocalStorage(page: Page, expected: number) { + return await page.waitForFunction(e => { + return JSON.parse(localStorage['react-todos']).length === e; + }, expected); +} + +async function checkNumberOfCompletedTodosInLocalStorage(page: Page, expected: number) { + return await page.waitForFunction(e => { + return JSON.parse(localStorage['react-todos']).filter((todo: any) => todo.completed).length === e; + }, expected); +} + +async function checkTodosInLocalStorage(page: Page, title: string) { + return await page.waitForFunction(t => { + return JSON.parse(localStorage['react-todos']).map((todo: any) => todo.title).includes(t); + }, title); +} diff --git a/tests/example.spec.ts b/tests/example.spec.ts new file mode 100644 index 0000000..54a906a --- /dev/null +++ b/tests/example.spec.ts @@ -0,0 +1,18 @@ +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 b352151b9a5ad35d18930ed89b564226dcec5eae Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Mon, 5 May 2025 08:00:54 +0100 Subject: [PATCH 004/158] Tests --- .github/workflows/tests.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5521f45..1a1ad42 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -62,9 +62,7 @@ jobs: sed -i "s/database_name_here/${WP_DB_NAME}/" wordpress/wp-config.php sed -i "s/username_here/${WP_DB_USER}/" wordpress/wp-config.php sed -i "s/password_here/${WP_DB_PASS}/" wordpress/wp-config.php - echo "define( 'DB_HOST', '${WP_DB_HOST}' );" >> wordpress/wp-config.php - echo "define( 'WP_HOME', '${WP_SITE_URL}' );" >> wordpress/wp-config.php - echo "define( 'WP_SITEURL', '${WP_SITE_URL}' );" >> wordpress/wp-config.php + sed -i "s/localhost/${WP_DB_HOST}/" wordpress/wp-config.php - name: Install WordPress run: | From 9abc618177c87874fe8d2bdacce734319f927bcb Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Mon, 5 May 2025 08:04:06 +0100 Subject: [PATCH 005/158] Tests --- .github/workflows/release.yml | 2 +- .github/workflows/tests.yml | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2304f0a..5eca599 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v4 with: - version: 9 + version: 10 - name: Install Node.js LTS uses: actions/setup-node@v4 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1a1ad42..819023f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -90,15 +90,21 @@ jobs: php -S localhost:8888 -t wordpress > /dev/null 2>&1 & sleep 5 + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + - name: Setup Node uses: actions/setup-node@v4 with: - node-version: 20 + node-version: lts/* + cache: "pnpm" - name: Install Playwright and dependencies run: | - npm ci - npx playwright install --with-deps + pnpm install + pnpx playwright install --with-deps - name: Run Playwright tests run: npx playwright test From 2f4e920b037ab0b32d509e0be7558fb881a007c4 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Mon, 5 May 2025 08:09:39 +0100 Subject: [PATCH 006/158] Tests --- .github/workflows/tests.yml | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 819023f..3efd6c5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -6,7 +6,18 @@ on: jobs: e2e: + name: PHP ${{ matrix.php }} - WP ${{ matrix.wordpress }} runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: [ '7.4', '8.0', '8.1', '8.2' ] + wordpress: [ '5.9', '6.0', '6.3', '6.5.3' ] + exclude: + # Exclude older PHP versions with newer WordPress + - php: '7.4' + wordpress: '6.5.3' + services: mysql: image: mysql:8.0 @@ -21,7 +32,7 @@ jobs: --health-retries=5 env: - WP_VERSION: 6.5.3 + WP_VERSION: ${{ matrix.wordpress }} WP_SITE_URL: http://localhost:8888 WP_DB_NAME: wordpress WP_DB_USER: root @@ -35,7 +46,10 @@ jobs: - name: Set up PHP uses: shivammathur/setup-php@v2 with: - php-version: 8.2 + php-version: ${{ matrix.php }} + extensions: mysqli, zip, gd + coverage: none + tools: wp-cli - name: Install dependencies run: | @@ -47,7 +61,7 @@ jobs: uses: actions/cache@v3 with: path: wordpress - key: wp-${{ env.WP_VERSION }} + key: wp-${{ matrix.wordpress }}-php-${{ matrix.php }} - name: Download WordPress if: steps.cache-wordpress.outputs.cache-hit != 'true' @@ -63,12 +77,11 @@ jobs: sed -i "s/username_here/${WP_DB_USER}/" wordpress/wp-config.php sed -i "s/password_here/${WP_DB_PASS}/" wordpress/wp-config.php sed -i "s/localhost/${WP_DB_HOST}/" wordpress/wp-config.php + # Add WP_DEBUG settings + sed -i "/define( 'DB_COLLATE', '' );/a define( 'WP_DEBUG', true );\ndefine( 'WP_DEBUG_LOG', true );" wordpress/wp-config.php - name: Install WordPress run: | - curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar - chmod +x wp-cli.phar - sudo mv wp-cli.phar /usr/local/bin/wp wp core install \ --url="${WP_SITE_URL}" \ --title="Test Site" \ @@ -108,3 +121,13 @@ jobs: - name: Run Playwright tests run: npx playwright test + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results-php${{ matrix.php }}-wp${{ matrix.wordpress }} + path: | + playwright-report/ + test-results/ + retention-days: 30 From b36fb7467ec1d99b59f21b6bd575221587509a15 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Mon, 5 May 2025 08:16:38 +0100 Subject: [PATCH 007/158] Tests --- .gitignore | 1 + playwright.config.ts | 116 ++++++++++++++++++++++--------------------- 2 files changed, 60 insertions(+), 57 deletions(-) diff --git a/.gitignore b/.gitignore index 32e9c6c..fe0d0ec 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ node_modules/ /playwright-report/ /blob-report/ /playwright/.cache/ +tests-browser-state.json diff --git a/playwright.config.ts b/playwright.config.ts index a05d8b5..b335126 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,4 +1,4 @@ -import { defineConfig, devices } from '@playwright/test'; +import { defineConfig, devices } from "@playwright/test"; /** * Read environment variables from file. @@ -12,68 +12,70 @@ import { defineConfig, devices } from '@playwright/test'; * 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', + 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:8888", - /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: 'on-first-retry', - }, + storageState: "tests-browser-state.json", - /* Configure projects for major browsers */ - projects: [ - { - name: 'chromium', - use: { ...devices['Desktop Chrome'] }, + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: "on-first-retry" }, - { - name: 'firefox', - use: { ...devices['Desktop Firefox'] }, - }, + /* Configure projects for major browsers */ + projects: [ + { + name: "chromium", + use: { ...devices["Desktop Chrome"] } + }, - { - name: 'webkit', - use: { ...devices['Desktop Safari'] }, - }, + { + name: "firefox", + use: { ...devices["Desktop Firefox"] } + }, - /* Test against mobile viewports. */ - // { - // name: 'Mobile Chrome', - // use: { ...devices['Pixel 5'] }, - // }, - // { - // name: 'Mobile Safari', - // use: { ...devices['iPhone 12'] }, - // }, + { + name: "webkit", + use: { ...devices["Desktop Safari"] } + } - /* Test against branded browsers. */ - // { - // name: 'Microsoft Edge', - // use: { ...devices['Desktop Edge'], channel: 'msedge' }, - // }, - // { - // name: 'Google Chrome', - // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, - // }, - ], + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, - /* 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, - // }, + /* 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, + // }, }); From ea64fcac7ffa6f609c38d6660b8a3808f3d4d7d3 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Mon, 5 May 2025 08:22:12 +0100 Subject: [PATCH 008/158] Tests --- tests/example.spec.ts | 18 ------------------ tests/helpers/login.ts | 29 +++++++++++++++++++++++++++++ tests/wordpress-spec.ts | 12 ++++++++++++ 3 files changed, 41 insertions(+), 18 deletions(-) delete mode 100644 tests/example.spec.ts create mode 100644 tests/helpers/login.ts create mode 100644 tests/wordpress-spec.ts diff --git a/tests/example.spec.ts b/tests/example.spec.ts deleted file mode 100644 index 54a906a..0000000 --- a/tests/example.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -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(); -}); diff --git a/tests/helpers/login.ts b/tests/helpers/login.ts new file mode 100644 index 0000000..78516ed --- /dev/null +++ b/tests/helpers/login.ts @@ -0,0 +1,29 @@ +import { Browser, Page, BrowserContext } from "@playwright/test"; +import * as fs from "node:fs"; + +export async function loginToWordPress(browser: Browser, storagePath = "tests-browser-state.json") { + // Skip login if state already exists + if (fs.existsSync(storagePath)) return; + + const context = await browser.newContext(); + const page = await context.newPage(); + + await page.goto("/wp-login.php"); + await page.fill("#user_login", "your-username"); + await page.fill("#user_pass", "your-password"); + await page.click("#wp-submit"); + + await page.waitForURL("**/wp-admin/**"); + + await context.storageState({ path: storagePath }); + await context.close(); +} + +export async function createLoggedInPage( + browser: Browser, + storagePath = "storage/wordpress-auth.json" +): Promise<{ context: BrowserContext; page: Page }> { + const context = await browser.newContext({ storageState: storagePath }); + const page = await context.newPage(); + return { context, page }; +} diff --git a/tests/wordpress-spec.ts b/tests/wordpress-spec.ts new file mode 100644 index 0000000..36cd6f2 --- /dev/null +++ b/tests/wordpress-spec.ts @@ -0,0 +1,12 @@ +import { test, expect } from "@playwright/test"; + +test.beforeAll(async ({ browser }) => { + await loginToWordPress(browser); +}); + +test("Access dashboard", async ({ browser }) => { + const { page } = await createLoggedInPage(browser); + + await page.goto("/wp-admin/"); + await expect(page).toHaveURL(/wp-admin/); +}); From 095b3854cfa965c16b7ed1af2ebec929d6a89881 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Mon, 5 May 2025 22:21:27 +0100 Subject: [PATCH 009/158] Tests --- tests/wordpress-spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/wordpress-spec.ts b/tests/wordpress-spec.ts index 36cd6f2..d7c10c9 100644 --- a/tests/wordpress-spec.ts +++ b/tests/wordpress-spec.ts @@ -1,4 +1,5 @@ import { test, expect } from "@playwright/test"; +import { createLoggedInPage, loginToWordPress } from "./helpers/login"; test.beforeAll(async ({ browser }) => { await loginToWordPress(browser); From 809ee65cc2d764142f8ed8953ff2f8aa4883ded8 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Mon, 5 May 2025 22:41:14 +0100 Subject: [PATCH 010/158] wip --- .github/workflows/tests.yml | 4 ++-- package.json | 4 +++- tests/{wordpress-spec.ts => wordpress.spec.ts} | 0 3 files changed, 5 insertions(+), 3 deletions(-) rename tests/{wordpress-spec.ts => wordpress.spec.ts} (100%) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3efd6c5..a73cfca 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -117,10 +117,10 @@ jobs: - name: Install Playwright and dependencies run: | pnpm install - pnpx playwright install --with-deps + pnpm run tests:install - name: Run Playwright tests - run: npx playwright test + run: pnpm run tests - name: Upload test results if: always() diff --git a/package.json b/package.json index 64c348d..5248f40 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,9 @@ "private": true, "scripts": { "dev": "tailwindcss -i resources/css/settings.css -o build/css/settings.css --watch", - "build": "tailwindcss build -i resources/css/settings.css -o build/css/settings.css" + "build": "tailwindcss build -i resources/css/settings.css -o build/css/settings.css", + "test:install": "playwright install --with-deps", + "test": "playwright test" }, "devDependencies": { "@playwright/test": "^1.52.0", diff --git a/tests/wordpress-spec.ts b/tests/wordpress.spec.ts similarity index 100% rename from tests/wordpress-spec.ts rename to tests/wordpress.spec.ts From d4911443a25391a5f4aa2ddaeebe152f5eb8448c Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Mon, 5 May 2025 22:42:52 +0100 Subject: [PATCH 011/158] Tests --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 5248f40..ad561bd 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,8 @@ "scripts": { "dev": "tailwindcss -i resources/css/settings.css -o build/css/settings.css --watch", "build": "tailwindcss build -i resources/css/settings.css -o build/css/settings.css", - "test:install": "playwright install --with-deps", - "test": "playwright test" + "tests:install": "playwright install --with-deps", + "tests": "playwright test" }, "devDependencies": { "@playwright/test": "^1.52.0", From 40cc2f5ad46e60c79354db862b207e1ecfb37acd Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 12 Jul 2025 15:21:21 +0100 Subject: [PATCH 012/158] wip --- playwright.config.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/playwright.config.ts b/playwright.config.ts index b335126..b669549 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -39,18 +39,18 @@ export default defineConfig({ { name: "chromium", use: { ...devices["Desktop Chrome"] } - }, - - { - name: "firefox", - use: { ...devices["Desktop Firefox"] } - }, - - { - name: "webkit", - use: { ...devices["Desktop Safari"] } } + // { + // name: "firefox", + // use: { ...devices["Desktop Firefox"] } + // }, + // + // { + // name: "webkit", + // use: { ...devices["Desktop Safari"] } + // } + /* Test against mobile viewports. */ // { // name: 'Mobile Chrome', From 461f811aae60b9c2d1b0290ea2713def7e56562b Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Mon, 13 Oct 2025 13:43:47 +0100 Subject: [PATCH 013/158] deps --- package.json | 8 +- pnpm-lock.yaml | 316 ++++++++++++++++++++++++------------------------- 2 files changed, 160 insertions(+), 164 deletions(-) diff --git a/package.json b/package.json index ad561bd..36605e0 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,9 @@ "tests": "playwright test" }, "devDependencies": { - "@playwright/test": "^1.52.0", - "@tailwindcss/forms": "^0.5.8", - "@types/node": "^22.15.3", - "tailwindcss": "^3.4.10" + "@playwright/test": "^1.56.0", + "@tailwindcss/forms": "^0.5.10", + "@types/node": "^22.18.10", + "tailwindcss": "^3.4.18" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0113137..e7f1bc4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,17 +9,17 @@ importers: .: devDependencies: '@playwright/test': - specifier: ^1.52.0 - version: 1.52.0 + specifier: ^1.56.0 + version: 1.56.0 '@tailwindcss/forms': - specifier: ^0.5.8 - version: 0.5.8(tailwindcss@3.4.10) + specifier: ^0.5.10 + version: 0.5.10(tailwindcss@3.4.18(yaml@2.5.0)) '@types/node': - specifier: ^22.15.3 - version: 22.15.3 + specifier: ^22.18.10 + version: 22.18.10 tailwindcss: - specifier: ^3.4.10 - version: 3.4.10 + specifier: ^3.4.18 + version: 3.4.18(yaml@2.5.0) packages: @@ -31,23 +31,18 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} - '@jridgewell/gen-mapping@0.3.5': - resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} - engines: {node: '>=6.0.0'} + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - '@jridgewell/set-array@1.2.1': - resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.0': - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - '@jridgewell/trace-mapping@0.3.25': - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -65,33 +60,33 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@playwright/test@1.52.0': - resolution: {integrity: sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==} + '@playwright/test@1.56.0': + resolution: {integrity: sha512-Tzh95Twig7hUwwNe381/K3PggZBZblKUe2wv25oIpzWLr6Z0m4KgV1ZVIjnR6GM9ANEqjZD7XsZEa6JL/7YEgg==} engines: {node: '>=18'} hasBin: true - '@tailwindcss/forms@0.5.8': - resolution: {integrity: sha512-DJs7B7NPD0JH7BVvdHWNviWmunlFhuEkz7FyFxE4japOWYMLl9b1D6+Z9mivJJPWr6AEbmlPqgiFRyLwFB1SgQ==} + '@tailwindcss/forms@0.5.10': + resolution: {integrity: sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==} peerDependencies: - tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20' + tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1' - '@types/node@22.15.3': - resolution: {integrity: sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==} + '@types/node@22.18.10': + resolution: {integrity: sha512-anNG/V/Efn/YZY4pRzbACnKxNKoBng2VTFydVu8RRs5hQjikP8CQfaeAV59VFSCzKNp90mXiVXW2QzV56rwMrg==} ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - ansi-regex@6.0.1: - resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} - ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} any-promise@1.3.0: @@ -111,8 +106,8 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} - brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} @@ -137,8 +132,8 @@ packages: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} - cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} cssesc@3.0.0: @@ -161,19 +156,19 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} - fastq@1.17.1: - resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - foreground-child@3.3.0: - resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} fsevents@2.3.2: @@ -209,8 +204,8 @@ packages: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} - is-core-module@2.15.1: - resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} is-extglob@2.1.1: @@ -235,16 +230,12 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jiti@1.21.6: - resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} + jiti@1.21.7: + resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} hasBin: true - lilconfig@2.1.0: - resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} - engines: {node: '>=10'} - - lilconfig@3.1.2: - resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} lines-and-columns@1.2.4: @@ -276,8 +267,8 @@ packages: mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - nanoid@3.3.7: - resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -293,8 +284,8 @@ packages: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} - package-json-from-dist@1.0.0: - resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} @@ -307,8 +298,8 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} - picocolors@1.1.0: - resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -318,17 +309,17 @@ packages: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} - pirates@4.0.6: - resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} - playwright-core@1.52.0: - resolution: {integrity: sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==} + playwright-core@1.56.0: + resolution: {integrity: sha512-1SXl7pMfemAMSDn5rkPeZljxOCYAmQnYLBTExuh6E8USHXGSX3dx6lYZN/xPpTz1vimXmPA9CDnILvmJaB8aSQ==} engines: {node: '>=18'} hasBin: true - playwright@1.52.0: - resolution: {integrity: sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==} + playwright@1.56.0: + resolution: {integrity: sha512-X5Q1b8lOdWIE4KAoHpW3SE8HvUB+ZZsUoN64ZhjnN8dOb1UpujxBtENGiZFE+9F/yhzJwYa+ca3u43FeLbboHA==} engines: {node: '>=18'} hasBin: true @@ -338,22 +329,28 @@ packages: peerDependencies: postcss: ^8.0.0 - postcss-js@4.0.1: - resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} + postcss-js@4.1.0: + resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==} engines: {node: ^12 || ^14 || >= 16} peerDependencies: postcss: ^8.4.21 - postcss-load-config@4.0.2: - resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} - engines: {node: '>= 14'} + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} peerDependencies: + jiti: '>=1.21.0' postcss: '>=8.0.9' - ts-node: '>=9.0.0' + tsx: ^4.8.1 + yaml: ^2.4.2 peerDependenciesMeta: + jiti: + optional: true postcss: optional: true - ts-node: + tsx: + optional: true + yaml: optional: true postcss-nested@6.2.0: @@ -369,8 +366,8 @@ packages: postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.4.44: - resolution: {integrity: sha512-Aweb9unOEpQ3ezu4Q00DPvvM2ZTUitJdNKeP/+uQgr1IBIqu574IaZoURId7BKtWMREwzKa9OgzPzezWGPWFQw==} + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} queue-microtask@1.2.3: @@ -383,12 +380,13 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} - resolve@1.22.8: - resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} hasBin: true - reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} run-parallel@1.2.0: @@ -406,8 +404,8 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - source-map-js@1.2.0: - resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} string-width@4.2.3: @@ -422,8 +420,8 @@ packages: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} - strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + strip-ansi@7.1.2: + resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} engines: {node: '>=12'} sucrase@3.35.0: @@ -435,8 +433,8 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - tailwindcss@3.4.10: - resolution: {integrity: sha512-KWZkVPm7yJRhdu4SRSl9d4AK2wM3a50UsvgHZO7xY77NQr2V+fIrEuoDGQcbvswWvFGbS2f6e+jC/6WJm1Dl0w==} + tailwindcss@3.4.18: + resolution: {integrity: sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==} engines: {node: '>=14.0.0'} hasBin: true @@ -486,27 +484,24 @@ snapshots: dependencies: string-width: 5.1.2 string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.0 + strip-ansi: 7.1.2 strip-ansi-cjs: strip-ansi@6.0.1 wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 - '@jridgewell/gen-mapping@0.3.5': + '@jridgewell/gen-mapping@0.3.13': dependencies: - '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.0 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 '@jridgewell/resolve-uri@3.1.2': {} - '@jridgewell/set-array@1.2.1': {} - - '@jridgewell/sourcemap-codec@1.5.0': {} + '@jridgewell/sourcemap-codec@1.5.5': {} - '@jridgewell/trace-mapping@0.3.25': + '@jridgewell/trace-mapping@0.3.31': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.5 '@nodelib/fs.scandir@2.1.5': dependencies: @@ -518,33 +513,33 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.17.1 + fastq: 1.19.1 '@pkgjs/parseargs@0.11.0': optional: true - '@playwright/test@1.52.0': + '@playwright/test@1.56.0': dependencies: - playwright: 1.52.0 + playwright: 1.56.0 - '@tailwindcss/forms@0.5.8(tailwindcss@3.4.10)': + '@tailwindcss/forms@0.5.10(tailwindcss@3.4.18(yaml@2.5.0))': dependencies: mini-svg-data-uri: 1.4.4 - tailwindcss: 3.4.10 + tailwindcss: 3.4.18(yaml@2.5.0) - '@types/node@22.15.3': + '@types/node@22.18.10': dependencies: undici-types: 6.21.0 ansi-regex@5.0.1: {} - ansi-regex@6.0.1: {} + ansi-regex@6.2.2: {} ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 - ansi-styles@6.2.1: {} + ansi-styles@6.2.3: {} any-promise@1.3.0: {} @@ -559,7 +554,7 @@ snapshots: binary-extensions@2.3.0: {} - brace-expansion@2.0.1: + brace-expansion@2.0.2: dependencies: balanced-match: 1.0.2 @@ -589,7 +584,7 @@ snapshots: commander@4.1.1: {} - cross-spawn@7.0.3: + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 @@ -607,7 +602,7 @@ snapshots: emoji-regex@9.2.2: {} - fast-glob@3.3.2: + fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 @@ -615,17 +610,17 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.8 - fastq@1.17.1: + fastq@1.19.1: dependencies: - reusify: 1.0.4 + reusify: 1.1.0 fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 - foreground-child@3.3.0: + foreground-child@3.3.1: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 signal-exit: 4.1.0 fsevents@2.3.2: @@ -646,11 +641,11 @@ snapshots: glob@10.4.5: dependencies: - foreground-child: 3.3.0 + foreground-child: 3.3.1 jackspeak: 3.4.3 minimatch: 9.0.5 minipass: 7.1.2 - package-json-from-dist: 1.0.0 + package-json-from-dist: 1.0.1 path-scurry: 1.11.1 hasown@2.0.2: @@ -661,7 +656,7 @@ snapshots: dependencies: binary-extensions: 2.3.0 - is-core-module@2.15.1: + is-core-module@2.16.1: dependencies: hasown: 2.0.2 @@ -683,11 +678,9 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jiti@1.21.6: {} + jiti@1.21.7: {} - lilconfig@2.1.0: {} - - lilconfig@3.1.2: {} + lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} @@ -704,7 +697,7 @@ snapshots: minimatch@9.0.5: dependencies: - brace-expansion: 2.0.1 + brace-expansion: 2.0.2 minipass@7.1.2: {} @@ -714,7 +707,7 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 - nanoid@3.3.7: {} + nanoid@3.3.11: {} normalize-path@3.0.0: {} @@ -722,7 +715,7 @@ snapshots: object-hash@3.0.0: {} - package-json-from-dist@1.0.0: {} + package-json-from-dist@1.0.1: {} path-key@3.1.1: {} @@ -733,44 +726,45 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 - picocolors@1.1.0: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} pify@2.3.0: {} - pirates@4.0.6: {} + pirates@4.0.7: {} - playwright-core@1.52.0: {} + playwright-core@1.56.0: {} - playwright@1.52.0: + playwright@1.56.0: dependencies: - playwright-core: 1.52.0 + playwright-core: 1.56.0 optionalDependencies: fsevents: 2.3.2 - postcss-import@15.1.0(postcss@8.4.44): + postcss-import@15.1.0(postcss@8.5.6): dependencies: - postcss: 8.4.44 + postcss: 8.5.6 postcss-value-parser: 4.2.0 read-cache: 1.0.0 - resolve: 1.22.8 + resolve: 1.22.10 - postcss-js@4.0.1(postcss@8.4.44): + postcss-js@4.1.0(postcss@8.5.6): dependencies: camelcase-css: 2.0.1 - postcss: 8.4.44 + postcss: 8.5.6 - postcss-load-config@4.0.2(postcss@8.4.44): + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(yaml@2.5.0): dependencies: - lilconfig: 3.1.2 - yaml: 2.5.0 + lilconfig: 3.1.3 optionalDependencies: - postcss: 8.4.44 + jiti: 1.21.7 + postcss: 8.5.6 + yaml: 2.5.0 - postcss-nested@6.2.0(postcss@8.4.44): + postcss-nested@6.2.0(postcss@8.5.6): dependencies: - postcss: 8.4.44 + postcss: 8.5.6 postcss-selector-parser: 6.1.2 postcss-selector-parser@6.1.2: @@ -780,11 +774,11 @@ snapshots: postcss-value-parser@4.2.0: {} - postcss@8.4.44: + postcss@8.5.6: dependencies: - nanoid: 3.3.7 - picocolors: 1.1.0 - source-map-js: 1.2.0 + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 queue-microtask@1.2.3: {} @@ -796,13 +790,13 @@ snapshots: dependencies: picomatch: 2.3.1 - resolve@1.22.8: + resolve@1.22.10: dependencies: - is-core-module: 2.15.1 + is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - reusify@1.0.4: {} + reusify@1.1.0: {} run-parallel@1.2.0: dependencies: @@ -816,7 +810,7 @@ snapshots: signal-exit@4.1.0: {} - source-map-js@1.2.0: {} + source-map-js@1.2.1: {} string-width@4.2.3: dependencies: @@ -828,54 +822,55 @@ snapshots: dependencies: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 - strip-ansi: 7.1.0 + strip-ansi: 7.1.2 strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 - strip-ansi@7.1.0: + strip-ansi@7.1.2: dependencies: - ansi-regex: 6.0.1 + ansi-regex: 6.2.2 sucrase@3.35.0: dependencies: - '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/gen-mapping': 0.3.13 commander: 4.1.1 glob: 10.4.5 lines-and-columns: 1.2.4 mz: 2.7.0 - pirates: 4.0.6 + pirates: 4.0.7 ts-interface-checker: 0.1.13 supports-preserve-symlinks-flag@1.0.0: {} - tailwindcss@3.4.10: + tailwindcss@3.4.18(yaml@2.5.0): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 chokidar: 3.6.0 didyoumean: 1.2.2 dlv: 1.1.3 - fast-glob: 3.3.2 + fast-glob: 3.3.3 glob-parent: 6.0.2 is-glob: 4.0.3 - jiti: 1.21.6 - lilconfig: 2.1.0 + jiti: 1.21.7 + lilconfig: 3.1.3 micromatch: 4.0.8 normalize-path: 3.0.0 object-hash: 3.0.0 - picocolors: 1.1.0 - postcss: 8.4.44 - postcss-import: 15.1.0(postcss@8.4.44) - postcss-js: 4.0.1(postcss@8.4.44) - postcss-load-config: 4.0.2(postcss@8.4.44) - postcss-nested: 6.2.0(postcss@8.4.44) + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-import: 15.1.0(postcss@8.5.6) + postcss-js: 4.1.0(postcss@8.5.6) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(yaml@2.5.0) + postcss-nested: 6.2.0(postcss@8.5.6) postcss-selector-parser: 6.1.2 - resolve: 1.22.8 + resolve: 1.22.10 sucrase: 3.35.0 transitivePeerDependencies: - - ts-node + - tsx + - yaml thenify-all@1.6.0: dependencies: @@ -907,8 +902,9 @@ snapshots: wrap-ansi@8.1.0: dependencies: - ansi-styles: 6.2.1 + ansi-styles: 6.2.3 string-width: 5.1.2 - strip-ansi: 7.1.0 + strip-ansi: 7.1.2 - yaml@2.5.0: {} + yaml@2.5.0: + optional: true From 4cf87503bd7ee72892be28a4a87cf7015be68eab Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Mon, 13 Oct 2025 20:26:03 +0100 Subject: [PATCH 014/158] wip --- .github/workflows/tests.yml | 4 +- playwright.config.ts | 81 ---------------------------- tests-examples/demo-todo-app.spec.ts | 8 +-- tests/helpers/login.ts | 29 ---------- tests/wordpress.spec.ts | 13 ----- 5 files changed, 6 insertions(+), 129 deletions(-) delete mode 100644 playwright.config.ts delete mode 100644 tests/helpers/login.ts delete mode 100644 tests/wordpress.spec.ts diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a73cfca..103f507 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -33,7 +33,7 @@ jobs: env: WP_VERSION: ${{ matrix.wordpress }} - WP_SITE_URL: http://localhost:8888 + WP_SITE_URL: http://localhost:8100 WP_DB_NAME: wordpress WP_DB_USER: root WP_DB_PASS: root @@ -100,7 +100,7 @@ jobs: - name: Start PHP server run: | - php -S localhost:8888 -t wordpress > /dev/null 2>&1 & + php -S localhost:8100 -t wordpress > /dev/null 2>&1 & sleep 5 - name: Install pnpm diff --git a/playwright.config.ts b/playwright.config.ts deleted file mode 100644 index b669549..0000000 --- a/playwright.config.ts +++ /dev/null @@ -1,81 +0,0 @@ -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:8888", - - storageState: "tests-browser-state.json", - - /* 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/tests-examples/demo-todo-app.spec.ts b/tests-examples/demo-todo-app.spec.ts index 8641cb5..3280d0a 100644 --- a/tests-examples/demo-todo-app.spec.ts +++ b/tests-examples/demo-todo-app.spec.ts @@ -56,7 +56,7 @@ test.describe('New Todo', () => { // create a todo count locator const todoCount = page.getByTestId('todo-count') - + // Check test using different methods. await expect(page.getByText('3 items left')).toBeVisible(); await expect(todoCount).toHaveText('3 items left'); @@ -260,7 +260,7 @@ test.describe('Counter', () => { test('should display the current number of todo items', async ({ page }) => { // create a new todo locator const newTodo = page.getByPlaceholder('What needs to be done?'); - + // create a todo count locator const todoCount = page.getByTestId('todo-count') @@ -350,7 +350,7 @@ test.describe('Routing', () => { }); test('should respect the back button', async ({ page }) => { - const todoItem = page.getByTestId('todo-item'); + const todoItem = page.getByTestId('todo-item'); await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); await checkNumberOfCompletedTodosInLocalStorage(page, 1); @@ -393,7 +393,7 @@ test.describe('Routing', () => { test('should highlight the currently applied filter', async ({ page }) => { await expect(page.getByRole('link', { name: 'All' })).toHaveClass('selected'); - + //create locators for active and completed links const activeLink = page.getByRole('link', { name: 'Active' }); const completedLink = page.getByRole('link', { name: 'Completed' }); diff --git a/tests/helpers/login.ts b/tests/helpers/login.ts deleted file mode 100644 index 78516ed..0000000 --- a/tests/helpers/login.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Browser, Page, BrowserContext } from "@playwright/test"; -import * as fs from "node:fs"; - -export async function loginToWordPress(browser: Browser, storagePath = "tests-browser-state.json") { - // Skip login if state already exists - if (fs.existsSync(storagePath)) return; - - const context = await browser.newContext(); - const page = await context.newPage(); - - await page.goto("/wp-login.php"); - await page.fill("#user_login", "your-username"); - await page.fill("#user_pass", "your-password"); - await page.click("#wp-submit"); - - await page.waitForURL("**/wp-admin/**"); - - await context.storageState({ path: storagePath }); - await context.close(); -} - -export async function createLoggedInPage( - browser: Browser, - storagePath = "storage/wordpress-auth.json" -): Promise<{ context: BrowserContext; page: Page }> { - const context = await browser.newContext({ storageState: storagePath }); - const page = await context.newPage(); - return { context, page }; -} diff --git a/tests/wordpress.spec.ts b/tests/wordpress.spec.ts deleted file mode 100644 index d7c10c9..0000000 --- a/tests/wordpress.spec.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { test, expect } from "@playwright/test"; -import { createLoggedInPage, loginToWordPress } from "./helpers/login"; - -test.beforeAll(async ({ browser }) => { - await loginToWordPress(browser); -}); - -test("Access dashboard", async ({ browser }) => { - const { page } = await createLoggedInPage(browser); - - await page.goto("/wp-admin/"); - await expect(page).toHaveURL(/wp-admin/); -}); From e5bc7f74f0c51b4052578a8013a3f169f095be72 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 14 Oct 2025 17:19:45 +0100 Subject: [PATCH 015/158] wip --- .github/workflows/tests.yml | 6 +- composer.json | 14 +- composer.lock | 5829 +++++++++++++++++++++++++- phpunit.xml | 17 + tests-examples/demo-todo-app.spec.ts | 437 -- tests/Browser/PluginSettingsTest.php | 11 + tests/Feature/ExampleTest.php | 5 + tests/Pest.php | 45 + tests/TestCase.php | 10 + tests/Unit/ExampleTest.php | 5 + 10 files changed, 5885 insertions(+), 494 deletions(-) create mode 100644 phpunit.xml delete mode 100644 tests-examples/demo-todo-app.spec.ts create mode 100644 tests/Browser/PluginSettingsTest.php create mode 100644 tests/Feature/ExampleTest.php create mode 100644 tests/Pest.php create mode 100644 tests/TestCase.php create mode 100644 tests/Unit/ExampleTest.php diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 103f507..d971681 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -73,9 +73,9 @@ jobs: - name: Configure WordPress run: | cp wordpress/wp-config-sample.php wordpress/wp-config.php - sed -i "s/database_name_here/${WP_DB_NAME}/" wordpress/wp-config.php - sed -i "s/username_here/${WP_DB_USER}/" wordpress/wp-config.php - sed -i "s/password_here/${WP_DB_PASS}/" wordpress/wp-config.php + sed -i "s/wordpress/${WP_DB_NAME}/" wordpress/wp-config.php + sed -i "s/root/${WP_DB_USER}/" wordpress/wp-config.php + sed -i "s/root/${WP_DB_PASS}/" wordpress/wp-config.php sed -i "s/localhost/${WP_DB_HOST}/" wordpress/wp-config.php # Add WP_DEBUG settings sed -i "/define( 'DB_COLLATE', '' );/a define( 'WP_DEBUG', true );\ndefine( 'WP_DEBUG_LOG', true );" wordpress/wp-config.php diff --git a/composer.json b/composer.json index a266a58..49fc0b6 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,17 @@ { "require-dev": { - "rector/rector": "^1.2" + "rector/rector": "^1.2", + "pestphp/pest": "^4.1", + "pestphp/pest-plugin-browser": "^4.1" + }, + "autoload": { + "psr-4": { + "Tests\\": "tests/" + } + }, + "config": { + "allow-plugins": { + "pestphp/pest-plugin": true + } } } diff --git a/composer.lock b/composer.lock index 6b98e03..1d3bd20 100644 --- a/composer.lock +++ b/composer.lock @@ -4,133 +4,5856 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "eb58f3061bde78d58fa424c73947025f", + "content-hash": "7866ac18a4b67095e6bf1a82087274ed", "packages": [], "packages-dev": [ + { + "name": "amphp/amp", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/amp.git", + "reference": "fa0ab33a6f47a82929c38d03ca47ebb71086a93f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/amp/zipball/fa0ab33a6f47a82929c38d03ca47ebb71086a93f", + "reference": "fa0ab33a6f47a82929c38d03ca47ebb71086a93f", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "phpunit/phpunit": "^9", + "psalm/phar": "5.23.1" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Future/functions.php", + "src/Internal/functions.php" + ], + "psr-4": { + "Amp\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + } + ], + "description": "A non-blocking concurrency framework for PHP applications.", + "homepage": "https://amphp.org/amp", + "keywords": [ + "async", + "asynchronous", + "awaitable", + "concurrency", + "event", + "event-loop", + "future", + "non-blocking", + "promise" + ], + "support": { + "issues": "https://github.com/amphp/amp/issues", + "source": "https://github.com/amphp/amp/tree/v3.1.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2025-08-27T21:42:00+00:00" + }, + { + "name": "amphp/byte-stream", + "version": "v2.1.2", + "source": { + "type": "git", + "url": "https://github.com/amphp/byte-stream.git", + "reference": "55a6bd071aec26fa2a3e002618c20c35e3df1b46" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/byte-stream/zipball/55a6bd071aec26fa2a3e002618c20c35e3df1b46", + "reference": "55a6bd071aec26fa2a3e002618c20c35e3df1b46", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/parser": "^1.1", + "amphp/pipeline": "^1", + "amphp/serialization": "^1", + "amphp/sync": "^2", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2.3" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "5.22.1" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Internal/functions.php" + ], + "psr-4": { + "Amp\\ByteStream\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A stream abstraction to make working with non-blocking I/O simple.", + "homepage": "https://amphp.org/byte-stream", + "keywords": [ + "amp", + "amphp", + "async", + "io", + "non-blocking", + "stream" + ], + "support": { + "issues": "https://github.com/amphp/byte-stream/issues", + "source": "https://github.com/amphp/byte-stream/tree/v2.1.2" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2025-03-16T17:10:27+00:00" + }, + { + "name": "amphp/cache", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/cache.git", + "reference": "46912e387e6aa94933b61ea1ead9cf7540b7797c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/cache/zipball/46912e387e6aa94933b61ea1ead9cf7540b7797c", + "reference": "46912e387e6aa94933b61ea1ead9cf7540b7797c", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/serialization": "^1", + "amphp/sync": "^2", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Cache\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + } + ], + "description": "A fiber-aware cache API based on Amp and Revolt.", + "homepage": "https://amphp.org/cache", + "support": { + "issues": "https://github.com/amphp/cache/issues", + "source": "https://github.com/amphp/cache/tree/v2.0.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-04-19T03:38:06+00:00" + }, + { + "name": "amphp/dns", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/dns.git", + "reference": "78eb3db5fc69bf2fc0cb503c4fcba667bc223c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/dns/zipball/78eb3db5fc69bf2fc0cb503c4fcba667bc223c71", + "reference": "78eb3db5fc69bf2fc0cb503c4fcba667bc223c71", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/cache": "^2", + "amphp/parser": "^1", + "amphp/process": "^2", + "daverandom/libdns": "^2.0.2", + "ext-filter": "*", + "ext-json": "*", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "5.20" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Dns\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Wright", + "email": "addr@daverandom.com" + }, + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "Async DNS resolution for Amp.", + "homepage": "https://github.com/amphp/dns", + "keywords": [ + "amp", + "amphp", + "async", + "client", + "dns", + "resolve" + ], + "support": { + "issues": "https://github.com/amphp/dns/issues", + "source": "https://github.com/amphp/dns/tree/v2.4.0" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2025-01-19T15:43:40+00:00" + }, + { + "name": "amphp/hpack", + "version": "v3.2.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/hpack.git", + "reference": "4f293064b15682a2b178b1367ddf0b8b5feb0239" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/hpack/zipball/4f293064b15682a2b178b1367ddf0b8b5feb0239", + "reference": "4f293064b15682a2b178b1367ddf0b8b5feb0239", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "http2jp/hpack-test-case": "^1", + "nikic/php-fuzzer": "^0.0.10", + "phpunit/phpunit": "^7 | ^8 | ^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\Http\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Bob Weinand" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "HTTP/2 HPack implementation.", + "homepage": "https://github.com/amphp/hpack", + "keywords": [ + "headers", + "hpack", + "http-2" + ], + "support": { + "issues": "https://github.com/amphp/hpack/issues", + "source": "https://github.com/amphp/hpack/tree/v3.2.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-03-21T19:00:16+00:00" + }, + { + "name": "amphp/http", + "version": "v2.1.2", + "source": { + "type": "git", + "url": "https://github.com/amphp/http.git", + "reference": "3680d80bd38b5d6f3c2cef2214ca6dd6cef26588" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/http/zipball/3680d80bd38b5d6f3c2cef2214ca6dd6cef26588", + "reference": "3680d80bd38b5d6f3c2cef2214ca6dd6cef26588", + "shasum": "" + }, + "require": { + "amphp/hpack": "^3", + "amphp/parser": "^1.1", + "league/uri-components": "^2.4.2 | ^7.1", + "php": ">=8.1", + "psr/http-message": "^1 | ^2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "league/uri": "^6.8 | ^7.1", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.26.1" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Internal/constants.php" + ], + "psr-4": { + "Amp\\Http\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "Basic HTTP primitives which can be shared by servers and clients.", + "support": { + "issues": "https://github.com/amphp/http/issues", + "source": "https://github.com/amphp/http/tree/v2.1.2" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-11-23T14:57:26+00:00" + }, + { + "name": "amphp/http-client", + "version": "v5.3.4", + "source": { + "type": "git", + "url": "https://github.com/amphp/http-client.git", + "reference": "75ad21574fd632594a2dd914496647816d5106bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/http-client/zipball/75ad21574fd632594a2dd914496647816d5106bc", + "reference": "75ad21574fd632594a2dd914496647816d5106bc", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/hpack": "^3", + "amphp/http": "^2", + "amphp/pipeline": "^1", + "amphp/socket": "^2", + "amphp/sync": "^2", + "league/uri": "^7", + "league/uri-components": "^7", + "league/uri-interfaces": "^7.1", + "php": ">=8.1", + "psr/http-message": "^1 | ^2", + "revolt/event-loop": "^1" + }, + "conflict": { + "amphp/file": "<3 | >=5" + }, + "require-dev": { + "amphp/file": "^3 | ^4", + "amphp/http-server": "^3", + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "ext-json": "*", + "kelunik/link-header-rfc5988": "^1", + "laminas/laminas-diactoros": "^2.3", + "phpunit/phpunit": "^9", + "psalm/phar": "~5.23" + }, + "suggest": { + "amphp/file": "Required for file request bodies and HTTP archive logging", + "ext-json": "Required for logging HTTP archives", + "ext-zlib": "Allows using compression for response bodies." + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Internal/functions.php" + ], + "psr-4": { + "Amp\\Http\\Client\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@gmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "An advanced async HTTP client library for PHP, enabling efficient, non-blocking, and concurrent requests and responses.", + "homepage": "https://amphp.org/http-client", + "keywords": [ + "async", + "client", + "concurrent", + "http", + "non-blocking", + "rest" + ], + "support": { + "issues": "https://github.com/amphp/http-client/issues", + "source": "https://github.com/amphp/http-client/tree/v5.3.4" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2025-08-16T20:41:23+00:00" + }, + { + "name": "amphp/http-server", + "version": "v3.4.3", + "source": { + "type": "git", + "url": "https://github.com/amphp/http-server.git", + "reference": "7aa962b0569f664af3ba23bc819f2a69884329cd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/http-server/zipball/7aa962b0569f664af3ba23bc819f2a69884329cd", + "reference": "7aa962b0569f664af3ba23bc819f2a69884329cd", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/cache": "^2", + "amphp/hpack": "^3", + "amphp/http": "^2", + "amphp/pipeline": "^1", + "amphp/socket": "^2.1", + "amphp/sync": "^2.2", + "league/uri": "^7.1", + "league/uri-interfaces": "^7.1", + "php": ">=8.1", + "psr/http-message": "^1 | ^2", + "psr/log": "^1 | ^2 | ^3", + "revolt/event-loop": "^1" + }, + "require-dev": { + "amphp/http-client": "^5", + "amphp/log": "^2", + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "league/uri-components": "^7.1", + "monolog/monolog": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "~5.23" + }, + "suggest": { + "ext-zlib": "Allows GZip compression of response bodies" + }, + "type": "library", + "autoload": { + "files": [ + "src/Driver/functions.php", + "src/Middleware/functions.php", + "src/functions.php" + ], + "psr-4": { + "Amp\\Http\\Server\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Bob Weinand" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "A non-blocking HTTP application server for PHP based on Amp.", + "homepage": "https://github.com/amphp/http-server", + "keywords": [ + "amp", + "amphp", + "async", + "http", + "non-blocking", + "server" + ], + "support": { + "issues": "https://github.com/amphp/http-server/issues", + "source": "https://github.com/amphp/http-server/tree/v3.4.3" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2025-05-18T15:43:42+00:00" + }, + { + "name": "amphp/parser", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/parser.git", + "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/parser/zipball/3cf1f8b32a0171d4b1bed93d25617637a77cded7", + "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7", + "shasum": "" + }, + "require": { + "php": ">=7.4" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Parser\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A generator parser to make streaming parsers simple.", + "homepage": "https://github.com/amphp/parser", + "keywords": [ + "async", + "non-blocking", + "parser", + "stream" + ], + "support": { + "issues": "https://github.com/amphp/parser/issues", + "source": "https://github.com/amphp/parser/tree/v1.1.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-03-21T19:16:53+00:00" + }, + { + "name": "amphp/pipeline", + "version": "v1.2.3", + "source": { + "type": "git", + "url": "https://github.com/amphp/pipeline.git", + "reference": "7b52598c2e9105ebcddf247fc523161581930367" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/pipeline/zipball/7b52598c2e9105ebcddf247fc523161581930367", + "reference": "7b52598c2e9105ebcddf247fc523161581930367", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "php": ">=8.1", + "revolt/event-loop": "^1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.18" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Pipeline\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Asynchronous iterators and operators.", + "homepage": "https://amphp.org/pipeline", + "keywords": [ + "amp", + "amphp", + "async", + "io", + "iterator", + "non-blocking" + ], + "support": { + "issues": "https://github.com/amphp/pipeline/issues", + "source": "https://github.com/amphp/pipeline/tree/v1.2.3" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2025-03-16T16:33:53+00:00" + }, + { + "name": "amphp/process", + "version": "v2.0.3", + "source": { + "type": "git", + "url": "https://github.com/amphp/process.git", + "reference": "52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/process/zipball/52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d", + "reference": "52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/sync": "^2", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.4" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Process\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A fiber-aware process manager based on Amp and Revolt.", + "homepage": "https://amphp.org/process", + "support": { + "issues": "https://github.com/amphp/process/issues", + "source": "https://github.com/amphp/process/tree/v2.0.3" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-04-19T03:13:44+00:00" + }, + { + "name": "amphp/serialization", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/serialization.git", + "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/serialization/zipball/693e77b2fb0b266c3c7d622317f881de44ae94a1", + "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "phpunit/phpunit": "^9 || ^8 || ^7" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Serialization\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Serialization tools for IPC and data storage in PHP.", + "homepage": "https://github.com/amphp/serialization", + "keywords": [ + "async", + "asynchronous", + "serialization", + "serialize" + ], + "support": { + "issues": "https://github.com/amphp/serialization/issues", + "source": "https://github.com/amphp/serialization/tree/master" + }, + "time": "2020-03-25T21:39:07+00:00" + }, + { + "name": "amphp/socket", + "version": "v2.3.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/socket.git", + "reference": "58e0422221825b79681b72c50c47a930be7bf1e1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/socket/zipball/58e0422221825b79681b72c50c47a930be7bf1e1", + "reference": "58e0422221825b79681b72c50c47a930be7bf1e1", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/dns": "^2", + "ext-openssl": "*", + "kelunik/certificate": "^1.1", + "league/uri": "^6.5 | ^7", + "league/uri-interfaces": "^2.3 | ^7", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "amphp/process": "^2", + "phpunit/phpunit": "^9", + "psalm/phar": "5.20" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php", + "src/Internal/functions.php", + "src/SocketAddress/functions.php" + ], + "psr-4": { + "Amp\\Socket\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@gmail.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Non-blocking socket connection / server implementations based on Amp and Revolt.", + "homepage": "https://github.com/amphp/socket", + "keywords": [ + "amp", + "async", + "encryption", + "non-blocking", + "sockets", + "tcp", + "tls" + ], + "support": { + "issues": "https://github.com/amphp/socket/issues", + "source": "https://github.com/amphp/socket/tree/v2.3.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-04-21T14:33:03+00:00" + }, + { + "name": "amphp/sync", + "version": "v2.3.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/sync.git", + "reference": "217097b785130d77cfcc58ff583cf26cd1770bf1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/sync/zipball/217097b785130d77cfcc58ff583cf26cd1770bf1", + "reference": "217097b785130d77cfcc58ff583cf26cd1770bf1", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/pipeline": "^1", + "amphp/serialization": "^1", + "php": ">=8.1", + "revolt/event-loop": "^1 || ^0.2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "5.23" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Sync\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Stephen Coakley", + "email": "me@stephencoakley.com" + } + ], + "description": "Non-blocking synchronization primitives for PHP based on Amp and Revolt.", + "homepage": "https://github.com/amphp/sync", + "keywords": [ + "async", + "asynchronous", + "mutex", + "semaphore", + "synchronization" + ], + "support": { + "issues": "https://github.com/amphp/sync/issues", + "source": "https://github.com/amphp/sync/tree/v2.3.0" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-08-03T19:31:26+00:00" + }, + { + "name": "amphp/websocket", + "version": "v2.0.4", + "source": { + "type": "git", + "url": "https://github.com/amphp/websocket.git", + "reference": "963904b6a883c4b62d9222d1d9749814fac96a3b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/websocket/zipball/963904b6a883c4b62d9222d1d9749814fac96a3b", + "reference": "963904b6a883c4b62d9222d1d9749814fac96a3b", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2", + "amphp/parser": "^1", + "amphp/pipeline": "^1", + "amphp/socket": "^2", + "php": ">=8.1", + "revolt/event-loop": "^1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.18" + }, + "suggest": { + "ext-zlib": "Required for compression" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Websocket\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + } + ], + "description": "Shared code for websocket servers and clients.", + "homepage": "https://github.com/amphp/websocket", + "keywords": [ + "amp", + "amphp", + "async", + "http", + "non-blocking", + "websocket" + ], + "support": { + "issues": "https://github.com/amphp/websocket/issues", + "source": "https://github.com/amphp/websocket/tree/v2.0.4" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2024-10-28T21:28:45+00:00" + }, + { + "name": "amphp/websocket-client", + "version": "v2.0.2", + "source": { + "type": "git", + "url": "https://github.com/amphp/websocket-client.git", + "reference": "dc033fdce0af56295a23f63ac4f579b34d470d6c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/websocket-client/zipball/dc033fdce0af56295a23f63ac4f579b34d470d6c", + "reference": "dc033fdce0af56295a23f63ac4f579b34d470d6c", + "shasum": "" + }, + "require": { + "amphp/amp": "^3", + "amphp/byte-stream": "^2.1", + "amphp/http": "^2.1", + "amphp/http-client": "^5", + "amphp/socket": "^2.2", + "amphp/websocket": "^2", + "league/uri": "^7.1", + "php": ">=8.1", + "psr/http-message": "^1|^2", + "revolt/event-loop": "^1" + }, + "require-dev": { + "amphp/http-server": "^3", + "amphp/php-cs-fixer-config": "^2", + "amphp/phpunit-util": "^3", + "amphp/websocket-server": "^3|^4", + "phpunit/phpunit": "^9", + "psalm/phar": "~5.26.1", + "psr/log": "^1" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Amp\\Websocket\\Client\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Async WebSocket client for PHP based on Amp.", + "keywords": [ + "amp", + "amphp", + "async", + "client", + "http", + "non-blocking", + "websocket" + ], + "support": { + "issues": "https://github.com/amphp/websocket-client/issues", + "source": "https://github.com/amphp/websocket-client/tree/v2.0.2" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2025-08-24T17:25:34+00:00" + }, + { + "name": "brianium/paratest", + "version": "v7.14.1", + "source": { + "type": "git", + "url": "https://github.com/paratestphp/paratest.git", + "reference": "e1a93c38a94f4808faf75552e835666d3a6f8bb2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paratestphp/paratest/zipball/e1a93c38a94f4808faf75552e835666d3a6f8bb2", + "reference": "e1a93c38a94f4808faf75552e835666d3a6f8bb2", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-simplexml": "*", + "fidry/cpu-core-counter": "^1.3.0", + "jean85/pretty-package-versions": "^2.1.1", + "php": "~8.3.0 || ~8.4.0 || ~8.5.0", + "phpunit/php-code-coverage": "^12.4.0", + "phpunit/php-file-iterator": "^6", + "phpunit/php-timer": "^8", + "phpunit/phpunit": "^12.4.0", + "sebastian/environment": "^8.0.3", + "symfony/console": "^6.4.20 || ^7.3.4", + "symfony/process": "^6.4.20 || ^7.3.4" + }, + "require-dev": { + "doctrine/coding-standard": "^14.0.0", + "ext-pcntl": "*", + "ext-pcov": "*", + "ext-posix": "*", + "phpstan/phpstan": "^2.1.30", + "phpstan/phpstan-deprecation-rules": "^2.0.3", + "phpstan/phpstan-phpunit": "^2.0.7", + "phpstan/phpstan-strict-rules": "^2.0.7", + "symfony/filesystem": "^6.4.13 || ^7.3.2" + }, + "bin": [ + "bin/paratest", + "bin/paratest_for_phpstorm" + ], + "type": "library", + "autoload": { + "psr-4": { + "ParaTest\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Scaturro", + "email": "scaturrob@gmail.com", + "role": "Developer" + }, + { + "name": "Filippo Tessarotto", + "email": "zoeslam@gmail.com", + "role": "Developer" + } + ], + "description": "Parallel testing for PHP", + "homepage": "https://github.com/paratestphp/paratest", + "keywords": [ + "concurrent", + "parallel", + "phpunit", + "testing" + ], + "support": { + "issues": "https://github.com/paratestphp/paratest/issues", + "source": "https://github.com/paratestphp/paratest/tree/v7.14.1" + }, + "funding": [ + { + "url": "https://github.com/sponsors/Slamdunk", + "type": "github" + }, + { + "url": "https://paypal.me/filippotessarotto", + "type": "paypal" + } + ], + "time": "2025-10-06T08:26:52+00:00" + }, + { + "name": "daverandom/libdns", + "version": "v2.1.0", + "source": { + "type": "git", + "url": "https://github.com/DaveRandom/LibDNS.git", + "reference": "b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/DaveRandom/LibDNS/zipball/b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a", + "reference": "b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "Required for IDN support" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "LibDNS\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "DNS protocol implementation written in pure PHP", + "keywords": [ + "dns" + ], + "support": { + "issues": "https://github.com/DaveRandom/LibDNS/issues", + "source": "https://github.com/DaveRandom/LibDNS/tree/v2.1.0" + }, + "time": "2024-04-12T12:12:48+00:00" + }, + { + "name": "doctrine/deprecations", + "version": "1.1.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", + "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "phpunit/phpunit": "<=7.5 || >=13" + }, + "require-dev": { + "doctrine/coding-standard": "^9 || ^12 || ^13", + "phpstan/phpstan": "1.4.10 || 2.1.11", + "phpstan/phpstan-phpunit": "^1.0 || ^2", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12", + "psr/log": "^1 || ^2 || ^3" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/1.1.5" + }, + "time": "2025-04-07T20:06:18+00:00" + }, + { + "name": "fidry/cpu-core-counter", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/theofidry/cpu-core-counter.git", + "reference": "db9508f7b1474469d9d3c53b86f817e344732678" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678", + "reference": "db9508f7b1474469d9d3c53b86f817e344732678", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "fidry/makefile": "^0.2.0", + "fidry/php-cs-fixer-config": "^1.1.2", + "phpstan/extension-installer": "^1.2.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^8.5.31 || ^9.5.26", + "webmozarts/strict-phpunit": "^7.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Fidry\\CpuCoreCounter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Théo FIDRY", + "email": "theo.fidry@gmail.com" + } + ], + "description": "Tiny utility to get the number of CPU cores.", + "keywords": [ + "CPU", + "core" + ], + "support": { + "issues": "https://github.com/theofidry/cpu-core-counter/issues", + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0" + }, + "funding": [ + { + "url": "https://github.com/theofidry", + "type": "github" + } + ], + "time": "2025-08-14T07:29:31+00:00" + }, + { + "name": "filp/whoops", + "version": "2.18.4", + "source": { + "type": "git", + "url": "https://github.com/filp/whoops.git", + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filp/whoops/zipball/d2102955e48b9fd9ab24280a7ad12ed552752c4d", + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3", + "symfony/var-dumper": "^4.0 || ^5.0" + }, + "suggest": { + "symfony/var-dumper": "Pretty print complex values better with var-dumper available", + "whoops/soap": "Formats errors as SOAP responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Whoops\\": "src/Whoops/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Filipe Dobreira", + "homepage": "https://github.com/filp", + "role": "Developer" + } + ], + "description": "php error handling for cool kids", + "homepage": "https://filp.github.io/whoops/", + "keywords": [ + "error", + "exception", + "handling", + "library", + "throwable", + "whoops" + ], + "support": { + "issues": "https://github.com/filp/whoops/issues", + "source": "https://github.com/filp/whoops/tree/2.18.4" + }, + "funding": [ + { + "url": "https://github.com/denis-sokolov", + "type": "github" + } + ], + "time": "2025-08-08T12:00:00+00:00" + }, + { + "name": "jean85/pretty-package-versions", + "version": "2.1.1", + "source": { + "type": "git", + "url": "https://github.com/Jean85/pretty-package-versions.git", + "reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/4d7aa5dab42e2a76d99559706022885de0e18e1a", + "reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.1.0", + "php": "^7.4|^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "jean85/composer-provided-replaced-stub-package": "^1.0", + "phpstan/phpstan": "^2.0", + "phpunit/phpunit": "^7.5|^8.5|^9.6", + "rector/rector": "^2.0", + "vimeo/psalm": "^4.3 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Jean85\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Lai", + "email": "alessandro.lai85@gmail.com" + } + ], + "description": "A library to get pretty versions strings of installed dependencies", + "keywords": [ + "composer", + "package", + "release", + "versions" + ], + "support": { + "issues": "https://github.com/Jean85/pretty-package-versions/issues", + "source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.1" + }, + "time": "2025-03-19T14:43:43+00:00" + }, + { + "name": "kelunik/certificate", + "version": "v1.1.3", + "source": { + "type": "git", + "url": "https://github.com/kelunik/certificate.git", + "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kelunik/certificate/zipball/7e00d498c264d5eb4f78c69f41c8bd6719c0199e", + "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "php": ">=7.0" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "^2", + "phpunit/phpunit": "^6 | 7 | ^8 | ^9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Kelunik\\Certificate\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Access certificate details and transform between different formats.", + "keywords": [ + "DER", + "certificate", + "certificates", + "openssl", + "pem", + "x509" + ], + "support": { + "issues": "https://github.com/kelunik/certificate/issues", + "source": "https://github.com/kelunik/certificate/tree/v1.1.3" + }, + "time": "2023-02-03T21:26:53+00:00" + }, + { + "name": "league/uri", + "version": "7.5.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri.git", + "reference": "81fb5145d2644324614cc532b28efd0215bda430" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430", + "reference": "81fb5145d2644324614cc532b28efd0215bda430", + "shasum": "" + }, + "require": { + "league/uri-interfaces": "^7.5", + "php": "^8.1" + }, + "conflict": { + "league/uri-schemes": "^1.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-fileinfo": "to create Data URI from file contennts", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", + "league/uri-components": "Needed to easily manipulate URI objects components", + "php-64bit": "to improve IPV4 host parsing", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "URI manipulation library", + "homepage": "https://uri.thephpleague.com", + "keywords": [ + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "middleware", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "uri-template", + "url", + "ws" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri/tree/7.5.1" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2024-12-08T08:40:02+00:00" + }, + { + "name": "league/uri-components", + "version": "7.5.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri-components.git", + "reference": "4aabf0e2f2f9421ffcacab35be33e4fb5e63c44f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri-components/zipball/4aabf0e2f2f9421ffcacab35be33e4fb5e63c44f", + "reference": "4aabf0e2f2f9421ffcacab35be33e4fb5e63c44f", + "shasum": "" + }, + "require": { + "league/uri": "^7.5", + "php": "^8.1" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-fileinfo": "to create Data URI from file contennts", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "ext-mbstring": "to use the sorting algorithm of URLSearchParams", + "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", + "php-64bit": "to improve IPV4 host parsing", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "URI components manipulation library", + "homepage": "http://uri.thephpleague.com", + "keywords": [ + "authority", + "components", + "fragment", + "host", + "middleware", + "modifier", + "path", + "port", + "query", + "rfc3986", + "scheme", + "uri", + "url", + "userinfo" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri-components/tree/7.5.1" + }, + "funding": [ + { + "url": "https://github.com/nyamsprod", + "type": "github" + } + ], + "time": "2024-12-08T08:40:02+00:00" + }, + { + "name": "league/uri-interfaces", + "version": "7.5.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri-interfaces.git", + "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", + "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^8.1", + "psr/http-factory": "^1", + "psr/http-message": "^1.1 || ^2.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "php-64bit": "to improve IPV4 host parsing", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "Common interfaces and classes for URI representation and interaction", + "homepage": "https://uri.thephpleague.com", + "keywords": [ + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "url", + "ws" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri-interfaces/tree/7.5.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2024-12-08T08:18:47+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.13.4", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-08-01T08:46:24+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.6.1", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", + "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1" + }, + "time": "2025-08-13T20:13:15+00:00" + }, + { + "name": "nunomaduro/collision", + "version": "v8.8.2", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/collision.git", + "reference": "60207965f9b7b7a4ce15a0f75d57f9dadb105bdb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/60207965f9b7b7a4ce15a0f75d57f9dadb105bdb", + "reference": "60207965f9b7b7a4ce15a0f75d57f9dadb105bdb", + "shasum": "" + }, + "require": { + "filp/whoops": "^2.18.1", + "nunomaduro/termwind": "^2.3.1", + "php": "^8.2.0", + "symfony/console": "^7.3.0" + }, + "conflict": { + "laravel/framework": "<11.44.2 || >=13.0.0", + "phpunit/phpunit": "<11.5.15 || >=13.0.0" + }, + "require-dev": { + "brianium/paratest": "^7.8.3", + "larastan/larastan": "^3.4.2", + "laravel/framework": "^11.44.2 || ^12.18", + "laravel/pint": "^1.22.1", + "laravel/sail": "^1.43.1", + "laravel/sanctum": "^4.1.1", + "laravel/tinker": "^2.10.1", + "orchestra/testbench-core": "^9.12.0 || ^10.4", + "pestphp/pest": "^3.8.2", + "sebastian/environment": "^7.2.1 || ^8.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider" + ] + }, + "branch-alias": { + "dev-8.x": "8.x-dev" + } + }, + "autoload": { + "files": [ + "./src/Adapters/Phpunit/Autoload.php" + ], + "psr-4": { + "NunoMaduro\\Collision\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Cli error handling for console/command-line PHP applications.", + "keywords": [ + "artisan", + "cli", + "command-line", + "console", + "dev", + "error", + "handling", + "laravel", + "laravel-zero", + "php", + "symfony" + ], + "support": { + "issues": "https://github.com/nunomaduro/collision/issues", + "source": "https://github.com/nunomaduro/collision" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://www.patreon.com/nunomaduro", + "type": "patreon" + } + ], + "time": "2025-06-25T02:12:12+00:00" + }, + { + "name": "nunomaduro/termwind", + "version": "v2.3.1", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/termwind.git", + "reference": "dfa08f390e509967a15c22493dc0bac5733d9123" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/dfa08f390e509967a15c22493dc0bac5733d9123", + "reference": "dfa08f390e509967a15c22493dc0bac5733d9123", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^8.2", + "symfony/console": "^7.2.6" + }, + "require-dev": { + "illuminate/console": "^11.44.7", + "laravel/pint": "^1.22.0", + "mockery/mockery": "^1.6.12", + "pestphp/pest": "^2.36.0 || ^3.8.2", + "phpstan/phpstan": "^1.12.25", + "phpstan/phpstan-strict-rules": "^1.6.2", + "symfony/var-dumper": "^7.2.6", + "thecodingmachine/phpstan-strict-rules": "^1.0.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Termwind\\Laravel\\TermwindServiceProvider" + ] + }, + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "files": [ + "src/Functions.php" + ], + "psr-4": { + "Termwind\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Its like Tailwind CSS, but for the console.", + "keywords": [ + "cli", + "console", + "css", + "package", + "php", + "style" + ], + "support": { + "issues": "https://github.com/nunomaduro/termwind/issues", + "source": "https://github.com/nunomaduro/termwind/tree/v2.3.1" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://github.com/xiCO2k", + "type": "github" + } + ], + "time": "2025-05-08T08:14:37+00:00" + }, + { + "name": "pestphp/pest", + "version": "v4.1.2", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest.git", + "reference": "08b09f2e98fc6830050c0237968b233768642d46" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest/zipball/08b09f2e98fc6830050c0237968b233768642d46", + "reference": "08b09f2e98fc6830050c0237968b233768642d46", + "shasum": "" + }, + "require": { + "brianium/paratest": "^7.14.0", + "nunomaduro/collision": "^8.8.2", + "nunomaduro/termwind": "^2.3.1", + "pestphp/pest-plugin": "^4.0.0", + "pestphp/pest-plugin-arch": "^4.0.0", + "pestphp/pest-plugin-mutate": "^4.0.1", + "pestphp/pest-plugin-profanity": "^4.1.0", + "php": "^8.3.0", + "phpunit/phpunit": "^12.4.0", + "symfony/process": "^7.3.4" + }, + "conflict": { + "filp/whoops": "<2.18.3", + "phpunit/phpunit": ">12.4.0", + "sebastian/exporter": "<7.0.0", + "webmozart/assert": "<1.11.0" + }, + "require-dev": { + "pestphp/pest-dev-tools": "^4.0.0", + "pestphp/pest-plugin-browser": "^4.1.1", + "pestphp/pest-plugin-type-coverage": "^4.0.2", + "psy/psysh": "^0.12.12" + }, + "bin": [ + "bin/pest" + ], + "type": "library", + "extra": { + "pest": { + "plugins": [ + "Pest\\Mutate\\Plugins\\Mutate", + "Pest\\Plugins\\Configuration", + "Pest\\Plugins\\Bail", + "Pest\\Plugins\\Cache", + "Pest\\Plugins\\Coverage", + "Pest\\Plugins\\Init", + "Pest\\Plugins\\Environment", + "Pest\\Plugins\\Help", + "Pest\\Plugins\\Memory", + "Pest\\Plugins\\Only", + "Pest\\Plugins\\Printer", + "Pest\\Plugins\\ProcessIsolation", + "Pest\\Plugins\\Profile", + "Pest\\Plugins\\Retry", + "Pest\\Plugins\\Snapshot", + "Pest\\Plugins\\Verbose", + "Pest\\Plugins\\Version", + "Pest\\Plugins\\Shard", + "Pest\\Plugins\\Parallel" + ] + }, + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "autoload": { + "files": [ + "src/Functions.php", + "src/Pest.php" + ], + "psr-4": { + "Pest\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "The elegant PHP Testing Framework.", + "keywords": [ + "framework", + "pest", + "php", + "test", + "testing", + "unit" + ], + "support": { + "issues": "https://github.com/pestphp/pest/issues", + "source": "https://github.com/pestphp/pest/tree/v4.1.2" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + } + ], + "time": "2025-10-05T19:09:49+00:00" + }, + { + "name": "pestphp/pest-plugin", + "version": "v4.0.0", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest-plugin.git", + "reference": "9d4b93d7f73d3f9c3189bb22c220fef271cdf568" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest-plugin/zipball/9d4b93d7f73d3f9c3189bb22c220fef271cdf568", + "reference": "9d4b93d7f73d3f9c3189bb22c220fef271cdf568", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.0.0", + "composer-runtime-api": "^2.2.2", + "php": "^8.3" + }, + "conflict": { + "pestphp/pest": "<4.0.0" + }, + "require-dev": { + "composer/composer": "^2.8.10", + "pestphp/pest": "^4.0.0", + "pestphp/pest-dev-tools": "^4.0.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Pest\\Plugin\\Manager" + }, + "autoload": { + "psr-4": { + "Pest\\Plugin\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The Pest plugin manager", + "keywords": [ + "framework", + "manager", + "pest", + "php", + "plugin", + "test", + "testing", + "unit" + ], + "support": { + "source": "https://github.com/pestphp/pest-plugin/tree/v4.0.0" + }, + "funding": [ + { + "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=66BYDWAT92N6L", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://www.patreon.com/nunomaduro", + "type": "patreon" + } + ], + "time": "2025-08-20T12:35:58+00:00" + }, + { + "name": "pestphp/pest-plugin-arch", + "version": "v4.0.0", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest-plugin-arch.git", + "reference": "25bb17e37920ccc35cbbcda3b00d596aadf3e58d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest-plugin-arch/zipball/25bb17e37920ccc35cbbcda3b00d596aadf3e58d", + "reference": "25bb17e37920ccc35cbbcda3b00d596aadf3e58d", + "shasum": "" + }, + "require": { + "pestphp/pest-plugin": "^4.0.0", + "php": "^8.3", + "ta-tikoma/phpunit-architecture-test": "^0.8.5" + }, + "require-dev": { + "pestphp/pest": "^4.0.0", + "pestphp/pest-dev-tools": "^4.0.0" + }, + "type": "library", + "extra": { + "pest": { + "plugins": [ + "Pest\\Arch\\Plugin" + ] + } + }, + "autoload": { + "files": [ + "src/Autoload.php" + ], + "psr-4": { + "Pest\\Arch\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The Arch plugin for Pest PHP.", + "keywords": [ + "arch", + "architecture", + "framework", + "pest", + "php", + "plugin", + "test", + "testing", + "unit" + ], + "support": { + "source": "https://github.com/pestphp/pest-plugin-arch/tree/v4.0.0" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + } + ], + "time": "2025-08-20T13:10:51+00:00" + }, + { + "name": "pestphp/pest-plugin-browser", + "version": "v4.1.1", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest-plugin-browser.git", + "reference": "da70fce21e4b33ba22bef1276f654e77676213d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest-plugin-browser/zipball/da70fce21e4b33ba22bef1276f654e77676213d7", + "reference": "da70fce21e4b33ba22bef1276f654e77676213d7", + "shasum": "" + }, + "require": { + "amphp/amp": "^3.1.1", + "amphp/http-server": "^3.4.3", + "amphp/websocket-client": "^2.0.2", + "ext-sockets": "*", + "pestphp/pest": "^4.1.0", + "pestphp/pest-plugin": "^4.0.0", + "php": "^8.3", + "symfony/process": "^7.3.4" + }, + "require-dev": { + "ext-pcntl": "*", + "ext-posix": "*", + "livewire/livewire": "^3.6.4", + "nunomaduro/collision": "^8.8.2", + "orchestra/testbench": "^10.6.0", + "pestphp/pest-dev-tools": "^4.0.0", + "pestphp/pest-plugin-laravel": "^4.0", + "pestphp/pest-plugin-type-coverage": "^4.0.2" + }, + "type": "library", + "extra": { + "pest": { + "plugins": [ + "Pest\\Browser\\Plugin" + ] + } + }, + "autoload": { + "files": [ + "src/Autoload.php" + ], + "psr-4": { + "Pest\\Browser\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Pest plugin to test browser interactions", + "keywords": [ + "browser", + "framework", + "pest", + "php", + "test", + "testing", + "unit" + ], + "support": { + "source": "https://github.com/pestphp/pest-plugin-browser/tree/v4.1.1" + }, + "funding": [ + { + "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=66BYDWAT92N6L", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://www.patreon.com/nunomaduro", + "type": "patreon" + } + ], + "time": "2025-09-29T01:31:33+00:00" + }, + { + "name": "pestphp/pest-plugin-mutate", + "version": "v4.0.1", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest-plugin-mutate.git", + "reference": "d9b32b60b2385e1688a68cc227594738ec26d96c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest-plugin-mutate/zipball/d9b32b60b2385e1688a68cc227594738ec26d96c", + "reference": "d9b32b60b2385e1688a68cc227594738ec26d96c", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.6.1", + "pestphp/pest-plugin": "^4.0.0", + "php": "^8.3", + "psr/simple-cache": "^3.0.0" + }, + "require-dev": { + "pestphp/pest": "^4.0.0", + "pestphp/pest-dev-tools": "^4.0.0", + "pestphp/pest-plugin-type-coverage": "^4.0.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Pest\\Mutate\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + }, + { + "name": "Sandro Gehri", + "email": "sandrogehri@gmail.com" + } + ], + "description": "Mutates your code to find untested cases", + "keywords": [ + "framework", + "mutate", + "mutation", + "pest", + "php", + "plugin", + "test", + "testing", + "unit" + ], + "support": { + "source": "https://github.com/pestphp/pest-plugin-mutate/tree/v4.0.1" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/gehrisandro", + "type": "github" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + } + ], + "time": "2025-08-21T20:19:25+00:00" + }, + { + "name": "pestphp/pest-plugin-profanity", + "version": "v4.1.0", + "source": { + "type": "git", + "url": "https://github.com/pestphp/pest-plugin-profanity.git", + "reference": "e279c844b6868da92052be27b5202c2ad7216e80" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pestphp/pest-plugin-profanity/zipball/e279c844b6868da92052be27b5202c2ad7216e80", + "reference": "e279c844b6868da92052be27b5202c2ad7216e80", + "shasum": "" + }, + "require": { + "pestphp/pest-plugin": "^4.0.0", + "php": "^8.3" + }, + "require-dev": { + "faissaloux/pest-plugin-inside": "^1.9", + "pestphp/pest": "^4.0.0", + "pestphp/pest-dev-tools": "^4.0.0" + }, + "type": "library", + "extra": { + "pest": { + "plugins": [ + "Pest\\Profanity\\Plugin" + ] + } + }, + "autoload": { + "psr-4": { + "Pest\\Profanity\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The Pest Profanity Plugin", + "keywords": [ + "framework", + "pest", + "php", + "plugin", + "profanity", + "test", + "testing", + "unit" + ], + "support": { + "source": "https://github.com/pestphp/pest-plugin-profanity/tree/v4.1.0" + }, + "time": "2025-09-10T06:17:03+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.6.3", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94f8051919d1b0369a6bcc7931d679a511c03fe9", + "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.1", + "ext-filter": "*", + "php": "^7.4 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.7", + "phpstan/phpdoc-parser": "^1.7|^2.0", + "webmozart/assert": "^1.9.1" + }, + "require-dev": { + "mockery/mockery": "~1.3.5 || ~1.6.0", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-webmozart-assert": "^1.2", + "phpunit/phpunit": "^9.5", + "psalm/phar": "^5.26" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.3" + }, + "time": "2025-08-01T19:43:32+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.10.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a", + "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.0", + "php": "^7.3 || ^8.0", + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.18|^2.0" + }, + "require-dev": { + "ext-tokenizer": "*", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.13.9", + "vimeo/psalm": "^4.25" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0" + }, + "time": "2024-11-09T15:12:26+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/1e0cd5370df5dd2e556a36b9c62f62e555870495", + "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^5.3.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.0" + }, + "time": "2025-08-30T15:50:23+00:00" + }, { "name": "phpstan/phpstan", "version": "1.12.0", "source": { "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "384af967d35b2162f69526c7276acadce534d0e1" + "url": "https://github.com/phpstan/phpstan.git", + "reference": "384af967d35b2162f69526c7276acadce534d0e1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/384af967d35b2162f69526c7276acadce534d0e1", + "reference": "384af967d35b2162f69526c7276acadce534d0e1", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2024-08-27T09:18:05+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "12.4.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "67e8aed88f93d0e6e1cb7effe1a2dfc2fee6022c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/67e8aed88f93d0e6e1cb7effe1a2dfc2fee6022c", + "reference": "67e8aed88f93d0e6e1cb7effe1a2dfc2fee6022c", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.6.1", + "php": ">=8.3", + "phpunit/php-file-iterator": "^6.0", + "phpunit/php-text-template": "^5.0", + "sebastian/complexity": "^5.0", + "sebastian/environment": "^8.0.3", + "sebastian/lines-of-code": "^4.0", + "sebastian/version": "^6.0", + "theseer/tokenizer": "^1.2.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.3.7" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "12.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.4.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage", + "type": "tidelift" + } + ], + "time": "2025-09-24T13:44:41+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "961bc913d42fe24a257bfff826a5068079ac7782" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/961bc913d42fe24a257bfff826a5068079ac7782", + "reference": "961bc913d42fe24a257bfff826a5068079ac7782", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:58:37+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/12b54e689b07a25a9b41e57736dfab6ec9ae5406", + "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^12.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:58:58+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/e1367a453f0eda562eedb4f659e13aa900d66c53", + "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:59:16+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "8.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", + "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "8.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/8.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:59:38+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "12.4.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "f62aab5794e36ccd26860db2d1bbf89ac19028d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f62aab5794e36ccd26860db2d1bbf89ac19028d9", + "reference": "f62aab5794e36ccd26860db2d1bbf89ac19028d9", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.4", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=8.3", + "phpunit/php-code-coverage": "^12.4.0", + "phpunit/php-file-iterator": "^6.0.0", + "phpunit/php-invoker": "^6.0.0", + "phpunit/php-text-template": "^5.0.0", + "phpunit/php-timer": "^8.0.0", + "sebastian/cli-parser": "^4.2.0", + "sebastian/comparator": "^7.1.3", + "sebastian/diff": "^7.0.0", + "sebastian/environment": "^8.0.3", + "sebastian/exporter": "^7.0.2", + "sebastian/global-state": "^8.0.2", + "sebastian/object-enumerator": "^7.0.0", + "sebastian/type": "^6.0.3", + "sebastian/version": "^6.0.0", + "staabm/side-effects-detector": "^1.0.5" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "12.4-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/12.4.0" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2025-10-03T04:28:03+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "time": "2024-04-15T12:06:14+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, + { + "name": "psr/log", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.2" + }, + "time": "2024-09-11T13:17:53+00:00" + }, + { + "name": "psr/simple-cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" + }, + "time": "2021-10-29T13:26:27+00:00" + }, + { + "name": "rector/rector", + "version": "1.2.4", + "source": { + "type": "git", + "url": "https://github.com/rectorphp/rector.git", + "reference": "42a4aa23b48b4cfc8ebfeac2b570364e27744381" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/42a4aa23b48b4cfc8ebfeac2b570364e27744381", + "reference": "42a4aa23b48b4cfc8ebfeac2b570364e27744381", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0", + "phpstan/phpstan": "^1.11.11" + }, + "conflict": { + "rector/rector-doctrine": "*", + "rector/rector-downgrade-php": "*", + "rector/rector-phpunit": "*", + "rector/rector-symfony": "*" + }, + "suggest": { + "ext-dom": "To manipulate phpunit.xml via the custom-rule command" + }, + "bin": [ + "bin/rector" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Instant Upgrade and Automated Refactoring of any PHP code", + "keywords": [ + "automation", + "dev", + "migration", + "refactoring" + ], + "support": { + "issues": "https://github.com/rectorphp/rector/issues", + "source": "https://github.com/rectorphp/rector/tree/1.2.4" + }, + "funding": [ + { + "url": "https://github.com/tomasvotruba", + "type": "github" + } + ], + "time": "2024-08-23T09:03:01+00:00" + }, + { + "name": "revolt/event-loop", + "version": "v1.0.7", + "source": { + "type": "git", + "url": "https://github.com/revoltphp/event-loop.git", + "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/09bf1bf7f7f574453efe43044b06fafe12216eb3", + "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "ext-json": "*", + "jetbrains/phpstorm-stubs": "^2019.3", + "phpunit/phpunit": "^9", + "psalm/phar": "^5.15" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Revolt\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "ceesjank@gmail.com" + }, + { + "name": "Christian Lück", + "email": "christian@clue.engineering" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Rock-solid event loop for concurrent PHP applications.", + "keywords": [ + "async", + "asynchronous", + "concurrency", + "event", + "event-loop", + "non-blocking", + "scheduler" + ], + "support": { + "issues": "https://github.com/revoltphp/event-loop/issues", + "source": "https://github.com/revoltphp/event-loop/tree/v1.0.7" + }, + "time": "2025-01-25T19:27:39+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "4.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "90f41072d220e5c40df6e8635f5dafba2d9d4d04" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/90f41072d220e5c40df6e8635f5dafba2d9d4d04", + "reference": "90f41072d220e5c40df6e8635f5dafba2d9d4d04", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/4.2.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/cli-parser", + "type": "tidelift" + } + ], + "time": "2025-09-14T09:36:45+00:00" + }, + { + "name": "sebastian/comparator", + "version": "7.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "dc904b4bb3ab070865fa4068cd84f3da8b945148" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/dc904b4bb3ab070865fa4068cd84f3da8b945148", + "reference": "dc904b4bb3ab070865fa4068cd84f3da8b945148", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.3", + "sebastian/diff": "^7.0", + "sebastian/exporter": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^12.2" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/7.1.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" + } + ], + "time": "2025-08-20T11:27:00+00:00" + }, + { + "name": "sebastian/complexity", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/bad4316aba5303d0221f43f8cee37eb58d384bbb", + "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:55:25+00:00" + }, + { + "name": "sebastian/diff", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "7ab1ea946c012266ca32390913653d844ecd085f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f", + "reference": "7ab1ea946c012266ca32390913653d844ecd085f", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0", + "symfony/process": "^7.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/7.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:55:46+00:00" + }, + { + "name": "sebastian/environment", + "version": "8.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "24a711b5c916efc6d6e62aa65aa2ec98fef77f68" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/24a711b5c916efc6d6e62aa65aa2ec98fef77f68", + "reference": "24a711b5c916efc6d6e62aa65aa2ec98fef77f68", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "8.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/8.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/environment", + "type": "tidelift" + } + ], + "time": "2025-08-12T14:11:56+00:00" + }, + { + "name": "sebastian/exporter", + "version": "7.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "016951ae10980765e4e7aee491eb288c64e505b7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/016951ae10980765e4e7aee491eb288c64e505b7", + "reference": "016951ae10980765e4e7aee491eb288c64e505b7", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.3", + "sebastian/recursion-context": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/7.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "type": "tidelift" + } + ], + "time": "2025-09-24T06:16:11+00:00" + }, + { + "name": "sebastian/global-state", + "version": "8.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "ef1377171613d09edd25b7816f05be8313f9115d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/ef1377171613d09edd25b7816f05be8313f9115d", + "reference": "ef1377171613d09edd25b7816f05be8313f9115d", + "shasum": "" + }, + "require": { + "php": ">=8.3", + "sebastian/object-reflector": "^5.0", + "sebastian/recursion-context": "^7.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "8.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/8.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state", + "type": "tidelift" + } + ], + "time": "2025-08-29T11:29:25+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/97ffee3bcfb5805568d6af7f0f893678fc076d2f", + "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/4.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:57:28+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1effe8e9b8e068e9ae228e542d5d11b5d16db894", + "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894", + "shasum": "" + }, + "require": { + "php": ">=8.3", + "sebastian/object-reflector": "^5.0", + "sebastian/recursion-context": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/7.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:57:48+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "4bfa827c969c98be1e527abd576533293c634f6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/4bfa827c969c98be1e527abd576533293c634f6a", + "reference": "4bfa827c969c98be1e527abd576533293c634f6a", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:58:17+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "7.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/0b01998a7d5b1f122911a66bebcb8d46f0c82d8c", + "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/7.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "type": "tidelift" + } + ], + "time": "2025-08-13T04:44:59+00:00" + }, + { + "name": "sebastian/type", + "version": "6.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "e549163b9760b8f71f191651d22acf32d56d6d4d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/e549163b9760b8f71f191651d22acf32d56d6d4d", + "reference": "e549163b9760b8f71f191651d22acf32d56d6d4d", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/6.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/type", + "type": "tidelift" + } + ], + "time": "2025-08-09T06:57:12+00:00" + }, + { + "name": "sebastian/version", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/3e6ccf7657d4f0a59200564b08cead899313b53c", + "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T05:00:38+00:00" + }, + { + "name": "staabm/side-effects-detector", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + }, + "funding": [ + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2024-10-20T05:08:20+00:00" + }, + { + "name": "symfony/console", + "version": "v7.3.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/2b9c5fafbac0399a20a2e82429e2bd735dcfb7db", + "reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^7.2" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v7.3.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-09-22T15:31:00+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/finder", + "version": "v7.3.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe", + "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/filesystem": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v7.3.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-07-15T13:41:35+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-06-27T09:58:17+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/384af967d35b2162f69526c7276acadce534d0e1", - "reference": "384af967d35b2162f69526c7276acadce534d0e1", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", "shasum": "" }, "require": { - "php": "^7.2|^8.0" + "ext-iconv": "*", + "php": ">=7.2" }, - "conflict": { - "phpstan/phpstan-shim": "*" + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" }, - "bin": [ - "phpstan", - "phpstan.phar" - ], "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, "autoload": { "files": [ "bootstrap.php" - ] + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "PHPStan - PHP Static Analysis Tool", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", "keywords": [ - "dev", - "static analysis" + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" ], "support": { - "docs": "https://phpstan.org/user-guide/getting-started", - "forum": "https://github.com/phpstan/phpstan/discussions", - "issues": "https://github.com/phpstan/phpstan/issues", - "security": "https://github.com/phpstan/phpstan/security/policy", - "source": "https://github.com/phpstan/phpstan-src" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" }, "funding": [ { - "url": "https://github.com/ondrejmirtes", + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", "type": "github" }, { - "url": "https://github.com/phpstan", + "url": "https://github.com/nicolas-grekas", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "time": "2024-08-27T09:18:05+00:00" + "time": "2024-12-23T08:48:59+00:00" }, { - "name": "rector/rector", - "version": "1.2.4", + "name": "symfony/process", + "version": "v7.3.4", "source": { "type": "git", - "url": "https://github.com/rectorphp/rector.git", - "reference": "42a4aa23b48b4cfc8ebfeac2b570364e27744381" + "url": "https://github.com/symfony/process.git", + "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/42a4aa23b48b4cfc8ebfeac2b570364e27744381", - "reference": "42a4aa23b48b4cfc8ebfeac2b570364e27744381", + "url": "https://api.github.com/repos/symfony/process/zipball/f24f8f316367b30810810d4eb30c543d7003ff3b", + "reference": "f24f8f316367b30810810d4eb30c543d7003ff3b", "shasum": "" }, "require": { - "php": "^7.2|^8.0", - "phpstan/phpstan": "^1.11.11" + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v7.3.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-09-11T10:12:26+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { - "rector/rector-doctrine": "*", - "rector/rector-downgrade-php": "*", - "rector/rector-phpunit": "*", - "rector/rector-symfony": "*" + "ext-psr": "<1.1|>=2" }, - "suggest": { - "ext-dom": "To manipulate phpunit.xml via the custom-rule command" + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } }, - "bin": [ - "bin/rector" + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } ], + "time": "2025-04-25T09:37:31+00:00" + }, + { + "name": "symfony/string", + "version": "v7.3.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "f96476035142921000338bad71e5247fbc138872" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/f96476035142921000338bad71e5247fbc138872", + "reference": "f96476035142921000338bad71e5247fbc138872", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/emoji": "^7.1", + "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0" + }, "type": "library", "autoload": { "files": [ - "bootstrap.php" + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "Instant Upgrade and Automated Refactoring of any PHP code", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", "keywords": [ - "automation", - "dev", - "migration", - "refactoring" + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" ], "support": { - "issues": "https://github.com/rectorphp/rector/issues", - "source": "https://github.com/rectorphp/rector/tree/1.2.4" + "source": "https://github.com/symfony/string/tree/v7.3.4" }, "funding": [ { - "url": "https://github.com/tomasvotruba", + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "time": "2024-08-23T09:03:01+00:00" + "time": "2025-09-11T14:36:48+00:00" + }, + { + "name": "ta-tikoma/phpunit-architecture-test", + "version": "0.8.5", + "source": { + "type": "git", + "url": "https://github.com/ta-tikoma/phpunit-architecture-test.git", + "reference": "cf6fb197b676ba716837c886baca842e4db29005" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ta-tikoma/phpunit-architecture-test/zipball/cf6fb197b676ba716837c886baca842e4db29005", + "reference": "cf6fb197b676ba716837c886baca842e4db29005", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18.0 || ^5.0.0", + "php": "^8.1.0", + "phpdocumentor/reflection-docblock": "^5.3.0", + "phpunit/phpunit": "^10.5.5 || ^11.0.0 || ^12.0.0", + "symfony/finder": "^6.4.0 || ^7.0.0" + }, + "require-dev": { + "laravel/pint": "^1.13.7", + "phpstan/phpstan": "^1.10.52" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPUnit\\Architecture\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ni Shi", + "email": "futik0ma011@gmail.com" + }, + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Methods for testing application architecture", + "keywords": [ + "architecture", + "phpunit", + "stucture", + "test", + "testing" + ], + "support": { + "issues": "https://github.com/ta-tikoma/phpunit-architecture-test/issues", + "source": "https://github.com/ta-tikoma/phpunit-architecture-test/tree/0.8.5" + }, + "time": "2025-04-20T20:23:40+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:36:25+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": "^7.2 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "time": "2022-06-03T18:03:27+00:00" } ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, - "platform": [], - "platform-dev": [], + "platform": {}, + "platform-dev": {}, "plugin-api-version": "2.6.0" } diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..35cdfbb --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,17 @@ + + + + + ./tests + + + + + src + + + diff --git a/tests-examples/demo-todo-app.spec.ts b/tests-examples/demo-todo-app.spec.ts deleted file mode 100644 index 3280d0a..0000000 --- a/tests-examples/demo-todo-app.spec.ts +++ /dev/null @@ -1,437 +0,0 @@ -import { test, expect, type Page } from '@playwright/test'; - -test.beforeEach(async ({ page }) => { - await page.goto('https://demo.playwright.dev/todomvc'); -}); - -const TODO_ITEMS = [ - 'buy some cheese', - 'feed the cat', - 'book a doctors appointment' -] as const; - -test.describe('New Todo', () => { - test('should allow me to add todo items', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - // Create 1st todo. - await newTodo.fill(TODO_ITEMS[0]); - await newTodo.press('Enter'); - - // Make sure the list only has one todo item. - await expect(page.getByTestId('todo-title')).toHaveText([ - TODO_ITEMS[0] - ]); - - // Create 2nd todo. - await newTodo.fill(TODO_ITEMS[1]); - await newTodo.press('Enter'); - - // Make sure the list now has two todo items. - await expect(page.getByTestId('todo-title')).toHaveText([ - TODO_ITEMS[0], - TODO_ITEMS[1] - ]); - - await checkNumberOfTodosInLocalStorage(page, 2); - }); - - test('should clear text input field when an item is added', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - // Create one todo item. - await newTodo.fill(TODO_ITEMS[0]); - await newTodo.press('Enter'); - - // Check that input is empty. - await expect(newTodo).toBeEmpty(); - await checkNumberOfTodosInLocalStorage(page, 1); - }); - - test('should append new items to the bottom of the list', async ({ page }) => { - // Create 3 items. - await createDefaultTodos(page); - - // create a todo count locator - const todoCount = page.getByTestId('todo-count') - - // Check test using different methods. - await expect(page.getByText('3 items left')).toBeVisible(); - await expect(todoCount).toHaveText('3 items left'); - await expect(todoCount).toContainText('3'); - await expect(todoCount).toHaveText(/3/); - - // Check all items in one call. - await expect(page.getByTestId('todo-title')).toHaveText(TODO_ITEMS); - await checkNumberOfTodosInLocalStorage(page, 3); - }); -}); - -test.describe('Mark all as completed', () => { - test.beforeEach(async ({ page }) => { - await createDefaultTodos(page); - await checkNumberOfTodosInLocalStorage(page, 3); - }); - - test.afterEach(async ({ page }) => { - await checkNumberOfTodosInLocalStorage(page, 3); - }); - - test('should allow me to mark all items as completed', async ({ page }) => { - // Complete all todos. - await page.getByLabel('Mark all as complete').check(); - - // Ensure all todos have 'completed' class. - await expect(page.getByTestId('todo-item')).toHaveClass(['completed', 'completed', 'completed']); - await checkNumberOfCompletedTodosInLocalStorage(page, 3); - }); - - test('should allow me to clear the complete state of all items', async ({ page }) => { - const toggleAll = page.getByLabel('Mark all as complete'); - // Check and then immediately uncheck. - await toggleAll.check(); - await toggleAll.uncheck(); - - // Should be no completed classes. - await expect(page.getByTestId('todo-item')).toHaveClass(['', '', '']); - }); - - test('complete all checkbox should update state when items are completed / cleared', async ({ page }) => { - const toggleAll = page.getByLabel('Mark all as complete'); - await toggleAll.check(); - await expect(toggleAll).toBeChecked(); - await checkNumberOfCompletedTodosInLocalStorage(page, 3); - - // Uncheck first todo. - const firstTodo = page.getByTestId('todo-item').nth(0); - await firstTodo.getByRole('checkbox').uncheck(); - - // Reuse toggleAll locator and make sure its not checked. - await expect(toggleAll).not.toBeChecked(); - - await firstTodo.getByRole('checkbox').check(); - await checkNumberOfCompletedTodosInLocalStorage(page, 3); - - // Assert the toggle all is checked again. - await expect(toggleAll).toBeChecked(); - }); -}); - -test.describe('Item', () => { - - test('should allow me to mark items as complete', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - // Create two items. - for (const item of TODO_ITEMS.slice(0, 2)) { - await newTodo.fill(item); - await newTodo.press('Enter'); - } - - // Check first item. - const firstTodo = page.getByTestId('todo-item').nth(0); - await firstTodo.getByRole('checkbox').check(); - await expect(firstTodo).toHaveClass('completed'); - - // Check second item. - const secondTodo = page.getByTestId('todo-item').nth(1); - await expect(secondTodo).not.toHaveClass('completed'); - await secondTodo.getByRole('checkbox').check(); - - // Assert completed class. - await expect(firstTodo).toHaveClass('completed'); - await expect(secondTodo).toHaveClass('completed'); - }); - - test('should allow me to un-mark items as complete', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - // Create two items. - for (const item of TODO_ITEMS.slice(0, 2)) { - await newTodo.fill(item); - await newTodo.press('Enter'); - } - - const firstTodo = page.getByTestId('todo-item').nth(0); - const secondTodo = page.getByTestId('todo-item').nth(1); - const firstTodoCheckbox = firstTodo.getByRole('checkbox'); - - await firstTodoCheckbox.check(); - await expect(firstTodo).toHaveClass('completed'); - await expect(secondTodo).not.toHaveClass('completed'); - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - - await firstTodoCheckbox.uncheck(); - await expect(firstTodo).not.toHaveClass('completed'); - await expect(secondTodo).not.toHaveClass('completed'); - await checkNumberOfCompletedTodosInLocalStorage(page, 0); - }); - - test('should allow me to edit an item', async ({ page }) => { - await createDefaultTodos(page); - - const todoItems = page.getByTestId('todo-item'); - const secondTodo = todoItems.nth(1); - await secondTodo.dblclick(); - await expect(secondTodo.getByRole('textbox', { name: 'Edit' })).toHaveValue(TODO_ITEMS[1]); - await secondTodo.getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); - await secondTodo.getByRole('textbox', { name: 'Edit' }).press('Enter'); - - // Explicitly assert the new text value. - await expect(todoItems).toHaveText([ - TODO_ITEMS[0], - 'buy some sausages', - TODO_ITEMS[2] - ]); - await checkTodosInLocalStorage(page, 'buy some sausages'); - }); -}); - -test.describe('Editing', () => { - test.beforeEach(async ({ page }) => { - await createDefaultTodos(page); - await checkNumberOfTodosInLocalStorage(page, 3); - }); - - test('should hide other controls when editing', async ({ page }) => { - const todoItem = page.getByTestId('todo-item').nth(1); - await todoItem.dblclick(); - await expect(todoItem.getByRole('checkbox')).not.toBeVisible(); - await expect(todoItem.locator('label', { - hasText: TODO_ITEMS[1], - })).not.toBeVisible(); - await checkNumberOfTodosInLocalStorage(page, 3); - }); - - test('should save edits on blur', async ({ page }) => { - const todoItems = page.getByTestId('todo-item'); - await todoItems.nth(1).dblclick(); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).dispatchEvent('blur'); - - await expect(todoItems).toHaveText([ - TODO_ITEMS[0], - 'buy some sausages', - TODO_ITEMS[2], - ]); - await checkTodosInLocalStorage(page, 'buy some sausages'); - }); - - test('should trim entered text', async ({ page }) => { - const todoItems = page.getByTestId('todo-item'); - await todoItems.nth(1).dblclick(); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill(' buy some sausages '); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Enter'); - - await expect(todoItems).toHaveText([ - TODO_ITEMS[0], - 'buy some sausages', - TODO_ITEMS[2], - ]); - await checkTodosInLocalStorage(page, 'buy some sausages'); - }); - - test('should remove the item if an empty text string was entered', async ({ page }) => { - const todoItems = page.getByTestId('todo-item'); - await todoItems.nth(1).dblclick(); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill(''); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Enter'); - - await expect(todoItems).toHaveText([ - TODO_ITEMS[0], - TODO_ITEMS[2], - ]); - }); - - test('should cancel edits on escape', async ({ page }) => { - const todoItems = page.getByTestId('todo-item'); - await todoItems.nth(1).dblclick(); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).fill('buy some sausages'); - await todoItems.nth(1).getByRole('textbox', { name: 'Edit' }).press('Escape'); - await expect(todoItems).toHaveText(TODO_ITEMS); - }); -}); - -test.describe('Counter', () => { - test('should display the current number of todo items', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - // create a todo count locator - const todoCount = page.getByTestId('todo-count') - - await newTodo.fill(TODO_ITEMS[0]); - await newTodo.press('Enter'); - - await expect(todoCount).toContainText('1'); - - await newTodo.fill(TODO_ITEMS[1]); - await newTodo.press('Enter'); - await expect(todoCount).toContainText('2'); - - await checkNumberOfTodosInLocalStorage(page, 2); - }); -}); - -test.describe('Clear completed button', () => { - test.beforeEach(async ({ page }) => { - await createDefaultTodos(page); - }); - - test('should display the correct text', async ({ page }) => { - await page.locator('.todo-list li .toggle').first().check(); - await expect(page.getByRole('button', { name: 'Clear completed' })).toBeVisible(); - }); - - test('should remove completed items when clicked', async ({ page }) => { - const todoItems = page.getByTestId('todo-item'); - await todoItems.nth(1).getByRole('checkbox').check(); - await page.getByRole('button', { name: 'Clear completed' }).click(); - await expect(todoItems).toHaveCount(2); - await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]); - }); - - test('should be hidden when there are no items that are completed', async ({ page }) => { - await page.locator('.todo-list li .toggle').first().check(); - await page.getByRole('button', { name: 'Clear completed' }).click(); - await expect(page.getByRole('button', { name: 'Clear completed' })).toBeHidden(); - }); -}); - -test.describe('Persistence', () => { - test('should persist its data', async ({ page }) => { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - for (const item of TODO_ITEMS.slice(0, 2)) { - await newTodo.fill(item); - await newTodo.press('Enter'); - } - - const todoItems = page.getByTestId('todo-item'); - const firstTodoCheck = todoItems.nth(0).getByRole('checkbox'); - await firstTodoCheck.check(); - await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]); - await expect(firstTodoCheck).toBeChecked(); - await expect(todoItems).toHaveClass(['completed', '']); - - // Ensure there is 1 completed item. - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - - // Now reload. - await page.reload(); - await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]); - await expect(firstTodoCheck).toBeChecked(); - await expect(todoItems).toHaveClass(['completed', '']); - }); -}); - -test.describe('Routing', () => { - test.beforeEach(async ({ page }) => { - await createDefaultTodos(page); - // make sure the app had a chance to save updated todos in storage - // before navigating to a new view, otherwise the items can get lost :( - // in some frameworks like Durandal - await checkTodosInLocalStorage(page, TODO_ITEMS[0]); - }); - - test('should allow me to display active items', async ({ page }) => { - const todoItem = page.getByTestId('todo-item'); - await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); - - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - await page.getByRole('link', { name: 'Active' }).click(); - await expect(todoItem).toHaveCount(2); - await expect(todoItem).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]); - }); - - test('should respect the back button', async ({ page }) => { - const todoItem = page.getByTestId('todo-item'); - await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); - - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - - await test.step('Showing all items', async () => { - await page.getByRole('link', { name: 'All' }).click(); - await expect(todoItem).toHaveCount(3); - }); - - await test.step('Showing active items', async () => { - await page.getByRole('link', { name: 'Active' }).click(); - }); - - await test.step('Showing completed items', async () => { - await page.getByRole('link', { name: 'Completed' }).click(); - }); - - await expect(todoItem).toHaveCount(1); - await page.goBack(); - await expect(todoItem).toHaveCount(2); - await page.goBack(); - await expect(todoItem).toHaveCount(3); - }); - - test('should allow me to display completed items', async ({ page }) => { - await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - await page.getByRole('link', { name: 'Completed' }).click(); - await expect(page.getByTestId('todo-item')).toHaveCount(1); - }); - - test('should allow me to display all items', async ({ page }) => { - await page.getByTestId('todo-item').nth(1).getByRole('checkbox').check(); - await checkNumberOfCompletedTodosInLocalStorage(page, 1); - await page.getByRole('link', { name: 'Active' }).click(); - await page.getByRole('link', { name: 'Completed' }).click(); - await page.getByRole('link', { name: 'All' }).click(); - await expect(page.getByTestId('todo-item')).toHaveCount(3); - }); - - test('should highlight the currently applied filter', async ({ page }) => { - await expect(page.getByRole('link', { name: 'All' })).toHaveClass('selected'); - - //create locators for active and completed links - const activeLink = page.getByRole('link', { name: 'Active' }); - const completedLink = page.getByRole('link', { name: 'Completed' }); - await activeLink.click(); - - // Page change - active items. - await expect(activeLink).toHaveClass('selected'); - await completedLink.click(); - - // Page change - completed items. - await expect(completedLink).toHaveClass('selected'); - }); -}); - -async function createDefaultTodos(page: Page) { - // create a new todo locator - const newTodo = page.getByPlaceholder('What needs to be done?'); - - for (const item of TODO_ITEMS) { - await newTodo.fill(item); - await newTodo.press('Enter'); - } -} - -async function checkNumberOfTodosInLocalStorage(page: Page, expected: number) { - return await page.waitForFunction(e => { - return JSON.parse(localStorage['react-todos']).length === e; - }, expected); -} - -async function checkNumberOfCompletedTodosInLocalStorage(page: Page, expected: number) { - return await page.waitForFunction(e => { - return JSON.parse(localStorage['react-todos']).filter((todo: any) => todo.completed).length === e; - }, expected); -} - -async function checkTodosInLocalStorage(page: Page, title: string) { - return await page.waitForFunction(t => { - return JSON.parse(localStorage['react-todos']).map((todo: any) => todo.title).includes(t); - }, title); -} diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php new file mode 100644 index 0000000..d06db1e --- /dev/null +++ b/tests/Browser/PluginSettingsTest.php @@ -0,0 +1,11 @@ +fill('user_login', 'admin'); + $page->fill('user_pass', 'admin'); + $page->press('wp-submit'); + + $page->assertSee('Welcome to WordPress!'); +}); diff --git a/tests/Feature/ExampleTest.php b/tests/Feature/ExampleTest.php new file mode 100644 index 0000000..61cd84c --- /dev/null +++ b/tests/Feature/ExampleTest.php @@ -0,0 +1,5 @@ +toBeTrue(); +}); diff --git a/tests/Pest.php b/tests/Pest.php new file mode 100644 index 0000000..b239048 --- /dev/null +++ b/tests/Pest.php @@ -0,0 +1,45 @@ +extend(Tests\TestCase::class)->in('Feature'); + +/* +|-------------------------------------------------------------------------- +| Expectations +|-------------------------------------------------------------------------- +| +| When you're writing tests, you often need to check that values meet certain conditions. The +| "expect()" function gives you access to a set of "expectations" methods that you can use +| to assert different things. Of course, you may extend the Expectation API at any time. +| +*/ + +expect()->extend('toBeOne', function () { + return $this->toBe(1); +}); + +/* +|-------------------------------------------------------------------------- +| Functions +|-------------------------------------------------------------------------- +| +| While Pest is very powerful out-of-the-box, you may have some testing code specific to your +| project that you don't want to repeat in every file. Here you can also expose helpers as +| global functions to help you to reduce the number of lines of code in your test files. +| +*/ + +function something() +{ + // .. +} diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..cfb05b6 --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,10 @@ +toBeTrue(); +}); From af4a5bd46ef049080712f18b8f39750c5d54d3dc Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 14 Oct 2025 17:20:09 +0100 Subject: [PATCH 016/158] wip --- .github/workflows/tests.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d971681..8b41d0a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -128,6 +128,5 @@ jobs: with: name: test-results-php${{ matrix.php }}-wp${{ matrix.wordpress }} path: | - playwright-report/ - test-results/ + tests/Browser/Screenshots retention-days: 30 From 032bafb7b772fa207c63f06b33a42ff39bac7eb1 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 14 Oct 2025 17:21:03 +0100 Subject: [PATCH 017/158] wip --- .github/workflows/tests.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8b41d0a..bce868e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,8 +11,11 @@ jobs: strategy: fail-fast: false matrix: - php: [ '7.4', '8.0', '8.1', '8.2' ] - wordpress: [ '5.9', '6.0', '6.3', '6.5.3' ] +# temporary disabled for testing +# php: [ '7.4', '8.0', '8.1', '8.2' ] +# wordpress: [ '5.9', '6.0', '6.3', '6.5.3' ] + php: [ '8.4' ] + wordpress: [ '6.5' ] exclude: # Exclude older PHP versions with newer WordPress - php: '7.4' From 63cea2bf09ab64a3287a31ea737ff7ffd5235d04 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 14 Oct 2025 17:22:12 +0100 Subject: [PATCH 018/158] wip --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index bce868e..f38115f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -123,7 +123,7 @@ jobs: pnpm run tests:install - name: Run Playwright tests - run: pnpm run tests + run: ./vendor/bin/pest - name: Upload test results if: always() From c4376138bcd52c053d415a98932421ec4d064ad4 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 14 Oct 2025 17:26:32 +0100 Subject: [PATCH 019/158] wip --- .github/workflows/tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f38115f..0e70100 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -83,6 +83,9 @@ jobs: # Add WP_DEBUG settings sed -i "/define( 'DB_COLLATE', '' );/a define( 'WP_DEBUG', true );\ndefine( 'WP_DEBUG_LOG', true );" wordpress/wp-config.php + - name: Test config + run: wp config list --path=wordpress --allow-root + - name: Install WordPress run: | wp core install \ From 0c99be15eee41468aab5538a518fe21c59bfa002 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 14 Oct 2025 17:31:30 +0100 Subject: [PATCH 020/158] wip --- .github/workflows/tests.yml | 192 ++++++++++++++++++------------------ 1 file changed, 94 insertions(+), 98 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0e70100..2be64d0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,15 +11,15 @@ jobs: strategy: fail-fast: false matrix: -# temporary disabled for testing -# php: [ '7.4', '8.0', '8.1', '8.2' ] -# wordpress: [ '5.9', '6.0', '6.3', '6.5.3' ] + # temporary disabled for testing + # php: [ '7.4', '8.0', '8.1', '8.2' ] + # wordpress: [ '5.9', '6.0', '6.3', '6.5.3' ] php: [ '8.4' ] wordpress: [ '6.5' ] exclude: # Exclude older PHP versions with newer WordPress - - php: '7.4' - wordpress: '6.5.3' + - php: '7.4' + wordpress: '6.5.3' services: mysql: @@ -43,96 +43,92 @@ jobs: WP_DB_HOST: 127.0.0.1 steps: - - name: Checkout plugin - uses: actions/checkout@v4 - - - name: Set up PHP - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - extensions: mysqli, zip, gd - coverage: none - tools: wp-cli - - - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get install -y unzip curl jq - - - name: Cache WordPress archive - id: cache-wordpress - uses: actions/cache@v3 - with: - path: wordpress - key: wp-${{ matrix.wordpress }}-php-${{ matrix.php }} - - - name: Download WordPress - if: steps.cache-wordpress.outputs.cache-hit != 'true' - run: | - curl -O https://wordpress.org/wordpress-${WP_VERSION}.tar.gz - tar -xzf wordpress-${WP_VERSION}.tar.gz - rm wordpress-${WP_VERSION}.tar.gz - - - name: Configure WordPress - run: | - cp wordpress/wp-config-sample.php wordpress/wp-config.php - sed -i "s/wordpress/${WP_DB_NAME}/" wordpress/wp-config.php - sed -i "s/root/${WP_DB_USER}/" wordpress/wp-config.php - sed -i "s/root/${WP_DB_PASS}/" wordpress/wp-config.php - sed -i "s/localhost/${WP_DB_HOST}/" wordpress/wp-config.php - # Add WP_DEBUG settings - sed -i "/define( 'DB_COLLATE', '' );/a define( 'WP_DEBUG', true );\ndefine( 'WP_DEBUG_LOG', true );" wordpress/wp-config.php - - - name: Test config - run: wp config list --path=wordpress --allow-root - - - name: Install WordPress - run: | - wp core install \ - --url="${WP_SITE_URL}" \ - --title="Test Site" \ - --admin_user=admin \ - --admin_password=admin \ - --admin_email=test@example.com \ - --path=wordpress \ - --skip-email \ - --allow-root - - - name: Install plugin - run: | - PLUGIN_SLUG=$(basename "$GITHUB_WORKSPACE") - ln -s "$GITHUB_WORKSPACE" "wordpress/wp-content/plugins/simpleanalytics" - wp plugin activate simpleanalytics --path=wordpress --allow-root - - - name: Start PHP server - run: | - php -S localhost:8100 -t wordpress > /dev/null 2>&1 & - sleep 5 - - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - version: 10 - - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: lts/* - cache: "pnpm" - - - name: Install Playwright and dependencies - run: | - pnpm install - pnpm run tests:install - - - name: Run Playwright tests - run: ./vendor/bin/pest - - - name: Upload test results - if: always() - uses: actions/upload-artifact@v4 - with: - name: test-results-php${{ matrix.php }}-wp${{ matrix.wordpress }} - path: | - tests/Browser/Screenshots - retention-days: 30 + - name: Checkout plugin + uses: actions/checkout@v4 + + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: mysqli, zip, gd + coverage: none + tools: wp-cli + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y unzip curl jq + + - name: Cache WordPress archive + id: cache-wordpress + uses: actions/cache@v3 + with: + path: wordpress + key: wp-${{ matrix.wordpress }}-php-${{ matrix.php }} + + - name: Download WordPress + if: steps.cache-wordpress.outputs.cache-hit != 'true' + run: | + curl -O https://wordpress.org/wordpress-${WP_VERSION}.tar.gz + tar -xzf wordpress-${WP_VERSION}.tar.gz + rm wordpress-${WP_VERSION}.tar.gz + + - name: Install WordPress + run: | + wp config set DB_NAME "wordpress" --path=wordpress --allow-root + wp config set DB_USER "root" --path=wordpress --allow-root + wp config set DB_PASSWORD "root" --path=wordpress --allow-root + wp config set DB_HOST "localhost" --path=wordpress --allow-root + wp config set WP_DEBUG true --raw --path=wordpress --allow-root + wp config set WP_DEBUG_LOG true --raw --path=wordpress --allow-root + wp core install \ + --url="${WP_SITE_URL}" \ + --title="Test Site" \ + --admin_user=admin \ + --admin_password=admin \ + --admin_email=test@example.com \ + --path=wordpress \ + --skip-email \ + --allow-root + + - name: Show current config values + run: wp config list --path=wordpress --allow-root + + - name: Install plugin + run: | + PLUGIN_SLUG=$(basename "$GITHUB_WORKSPACE") + ln -s "$GITHUB_WORKSPACE" "wordpress/wp-content/plugins/simpleanalytics" + wp plugin activate simpleanalytics --path=wordpress --allow-root + + - name: Start PHP server + run: | + php -S localhost:8100 -t wordpress > /dev/null 2>&1 & + sleep 5 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: lts/* + cache: "pnpm" + + - name: Install Playwright and dependencies + run: | + pnpm install + pnpm run tests:install + + - name: Run Playwright tests + run: ./vendor/bin/pest + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results-php${{ matrix.php }}-wp${{ matrix.wordpress }} + path: | + tests/Browser/Screenshots + retention-days: 30 From 2281be08353c15d5fa2b507b2fa398d246fa7ed8 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 14 Oct 2025 17:33:12 +0100 Subject: [PATCH 021/158] wip --- .github/workflows/tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2be64d0..ab21c66 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -75,6 +75,7 @@ jobs: - name: Install WordPress run: | + cp wordpress/wp-config-sample.php wordpress/wp-config.php wp config set DB_NAME "wordpress" --path=wordpress --allow-root wp config set DB_USER "root" --path=wordpress --allow-root wp config set DB_PASSWORD "root" --path=wordpress --allow-root From 18b6af35bf6fda6e9cdcaa5b2222c7dea18f6780 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 14 Oct 2025 17:35:35 +0100 Subject: [PATCH 022/158] wip --- .github/workflows/tests.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ab21c66..631bda4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -76,10 +76,10 @@ jobs: - name: Install WordPress run: | cp wordpress/wp-config-sample.php wordpress/wp-config.php - wp config set DB_NAME "wordpress" --path=wordpress --allow-root - wp config set DB_USER "root" --path=wordpress --allow-root - wp config set DB_PASSWORD "root" --path=wordpress --allow-root - wp config set DB_HOST "localhost" --path=wordpress --allow-root + wp config set DB_NAME "$WP_DB_NAME" --path=wordpress --allow-root + wp config set DB_USER "$WP_DB_USER" --path=wordpress --allow-root + wp config set DB_PASSWORD "$WP_DB_PASS" --path=wordpress --allow-root + wp config set DB_HOST "$WP_DB_HOST" --path=wordpress --allow-root wp config set WP_DEBUG true --raw --path=wordpress --allow-root wp config set WP_DEBUG_LOG true --raw --path=wordpress --allow-root wp core install \ From 47b9e58181beadda762e4e6a4c7062abb42f57bb Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 14 Oct 2025 17:38:05 +0100 Subject: [PATCH 023/158] wip --- .github/workflows/tests.yml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 631bda4..cad09ca 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -75,13 +75,17 @@ jobs: - name: Install WordPress run: | - cp wordpress/wp-config-sample.php wordpress/wp-config.php - wp config set DB_NAME "$WP_DB_NAME" --path=wordpress --allow-root - wp config set DB_USER "$WP_DB_USER" --path=wordpress --allow-root - wp config set DB_PASSWORD "$WP_DB_PASS" --path=wordpress --allow-root - wp config set DB_HOST "$WP_DB_HOST" --path=wordpress --allow-root - wp config set WP_DEBUG true --raw --path=wordpress --allow-root - wp config set WP_DEBUG_LOG true --raw --path=wordpress --allow-root + wp config create \ + --dbname="$WP_DB_NAME" \ + --dbuser="$WP_DB_USER" \ + --dbpass="$WP_DB_PASS" \ + --dbhost="$WP_DB_HOST" \ + --path=wordpress \ + --skip-check \ + --extra-php < Date: Tue, 14 Oct 2025 17:39:38 +0100 Subject: [PATCH 024/158] wip --- .github/workflows/tests.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cad09ca..0aabba2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -81,11 +81,7 @@ jobs: --dbpass="$WP_DB_PASS" \ --dbhost="$WP_DB_HOST" \ --path=wordpress \ - --skip-check \ - --extra-php < Date: Tue, 14 Oct 2025 17:44:55 +0100 Subject: [PATCH 025/158] wip --- .github/workflows/tests.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0aabba2..97c7860 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -122,7 +122,16 @@ jobs: pnpm install pnpm run tests:install - - name: Run Playwright tests + - name: Cache composer dependencies + uses: actions/cache@v3 + with: + path: vendor + key: composer-${{ hashFiles('composer.lock') }} + + - name: Run composer install + run: composer install --no-progress --prefer-dist --no-interaction + + - name: Run Pest tests run: ./vendor/bin/pest - name: Upload test results From 1d66d422d0ba2239118fe7aaf82bd175d2e373f7 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 14 Oct 2025 17:49:07 +0100 Subject: [PATCH 026/158] wip --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 97c7860..c2a1493 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -103,7 +103,7 @@ jobs: - name: Start PHP server run: | - php -S localhost:8100 -t wordpress > /dev/null 2>&1 & + php -S 127.0.0.1:8100 -t wordpress > /dev/null 2>&1 & sleep 5 - name: Install pnpm From 22e31b081dfdde41fb7d1fd002f1130706d0973f Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 14 Oct 2025 17:57:20 +0100 Subject: [PATCH 027/158] wip --- .github/workflows/tests.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c2a1493..23fc8a6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -103,8 +103,7 @@ jobs: - name: Start PHP server run: | - php -S 127.0.0.1:8100 -t wordpress > /dev/null 2>&1 & - sleep 5 + php -S 127.0.0.1:8100 -t wordpress > /dev/null 2>&1 & until curl -sSf http://127.0.0.1:8100 > /dev/null; do sleep 0.2; done - name: Install pnpm uses: pnpm/action-setup@v4 From 12750034b3e7fa65ec8beab19a339c29407b327c Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 14 Oct 2025 18:00:09 +0100 Subject: [PATCH 028/158] wip --- .github/workflows/tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 23fc8a6..eb1eda5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -75,6 +75,7 @@ jobs: - name: Install WordPress run: | + rm wordpress/wp-config.php wp config create \ --dbname="$WP_DB_NAME" \ --dbuser="$WP_DB_USER" \ From ccb8064d95b1a0ce681984faa96c62c0e1c30afd Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 14 Oct 2025 22:05:12 +0100 Subject: [PATCH 029/158] wip --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index fe0d0ec..353c019 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ node_modules/ /blob-report/ /playwright/.cache/ tests-browser-state.json +tests/**/Screenshots From 95244acc0a80b3e14945428402581bf703b21522 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Wed, 15 Oct 2025 22:15:09 +0100 Subject: [PATCH 030/158] wip --- composer.json | 3 +- composer.lock | 89 +++++++++++++++++++++++++++- tests/Browser/PluginSettingsTest.php | 4 +- 3 files changed, 93 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 49fc0b6..f0a14a1 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,8 @@ "require-dev": { "rector/rector": "^1.2", "pestphp/pest": "^4.1", - "pestphp/pest-plugin-browser": "^4.1" + "pestphp/pest-plugin-browser": "^4.1", + "symfony/var-dumper": "^7.3" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 1d3bd20..3948cc4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7866ac18a4b67095e6bf1a82087274ed", + "content-hash": "f021bcb880511a080c31806eb76e1619", "packages": [], "packages-dev": [ { @@ -5680,6 +5680,93 @@ ], "time": "2025-09-11T14:36:48+00:00" }, + { + "name": "symfony/var-dumper", + "version": "v7.3.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb", + "reference": "b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/uid": "^6.4|^7.0", + "twig/twig": "^3.12" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v7.3.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-09-11T10:12:26+00:00" + }, { "name": "ta-tikoma/phpunit-architecture-test", "version": "0.8.5", diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index d06db1e..31c48e8 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -6,6 +6,8 @@ $page->fill('user_login', 'admin'); $page->fill('user_pass', 'admin'); $page->press('wp-submit'); - $page->assertSee('Welcome to WordPress!'); + + $page2 = visit('http://127.0.0.1:8100')->screenshot(); + expect($page2->content())->toContain(''); }); From 1f3bcfb2d32923b0f960ba7e522828e7fabf9577 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 28 Oct 2025 09:09:04 +0000 Subject: [PATCH 031/158] deps --- composer.lock | 87 ++++++++++++++++++++++++--------------------------- 1 file changed, 41 insertions(+), 46 deletions(-) diff --git a/composer.lock b/composer.lock index 3948cc4..a90792d 100644 --- a/composer.lock +++ b/composer.lock @@ -1982,16 +1982,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.6.1", + "version": "v5.6.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2" + "reference": "3a454ca033b9e06b63282ce19562e892747449bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", - "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb", + "reference": "3a454ca033b9e06b63282ce19562e892747449bb", "shasum": "" }, "require": { @@ -2034,9 +2034,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2" }, - "time": "2025-08-13T20:13:15+00:00" + "time": "2025-10-21T19:32:17+00:00" }, { "name": "nunomaduro/collision", @@ -2139,31 +2139,31 @@ }, { "name": "nunomaduro/termwind", - "version": "v2.3.1", + "version": "v2.3.2", "source": { "type": "git", "url": "https://github.com/nunomaduro/termwind.git", - "reference": "dfa08f390e509967a15c22493dc0bac5733d9123" + "reference": "eb61920a53057a7debd718a5b89c2178032b52c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/dfa08f390e509967a15c22493dc0bac5733d9123", - "reference": "dfa08f390e509967a15c22493dc0bac5733d9123", + "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/eb61920a53057a7debd718a5b89c2178032b52c0", + "reference": "eb61920a53057a7debd718a5b89c2178032b52c0", "shasum": "" }, "require": { "ext-mbstring": "*", "php": "^8.2", - "symfony/console": "^7.2.6" + "symfony/console": "^7.3.4" }, "require-dev": { - "illuminate/console": "^11.44.7", - "laravel/pint": "^1.22.0", + "illuminate/console": "^11.46.1", + "laravel/pint": "^1.25.1", "mockery/mockery": "^1.6.12", - "pestphp/pest": "^2.36.0 || ^3.8.2", - "phpstan/phpstan": "^1.12.25", + "pestphp/pest": "^2.36.0 || ^3.8.4", + "phpstan/phpstan": "^1.12.32", "phpstan/phpstan-strict-rules": "^1.6.2", - "symfony/var-dumper": "^7.2.6", + "symfony/var-dumper": "^7.3.4", "thecodingmachine/phpstan-strict-rules": "^1.0.0" }, "type": "library", @@ -2206,7 +2206,7 @@ ], "support": { "issues": "https://github.com/nunomaduro/termwind/issues", - "source": "https://github.com/nunomaduro/termwind/tree/v2.3.1" + "source": "https://github.com/nunomaduro/termwind/tree/v2.3.2" }, "funding": [ { @@ -2222,7 +2222,7 @@ "type": "github" } ], - "time": "2025-05-08T08:14:37+00:00" + "time": "2025-10-18T11:10:27+00:00" }, { "name": "pestphp/pest", @@ -3037,16 +3037,11 @@ }, { "name": "phpstan/phpstan", - "version": "1.12.0", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "384af967d35b2162f69526c7276acadce534d0e1" - }, + "version": "1.12.32", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/384af967d35b2162f69526c7276acadce534d0e1", - "reference": "384af967d35b2162f69526c7276acadce534d0e1", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/2770dcdf5078d0b0d53f94317e06affe88419aa8", + "reference": "2770dcdf5078d0b0d53f94317e06affe88419aa8", "shasum": "" }, "require": { @@ -3091,7 +3086,7 @@ "type": "github" } ], - "time": "2024-08-27T09:18:05+00:00" + "time": "2025-09-30T10:16:31+00:00" }, { "name": "phpunit/php-code-coverage", @@ -3796,21 +3791,21 @@ }, { "name": "rector/rector", - "version": "1.2.4", + "version": "1.2.10", "source": { "type": "git", "url": "https://github.com/rectorphp/rector.git", - "reference": "42a4aa23b48b4cfc8ebfeac2b570364e27744381" + "reference": "40f9cf38c05296bd32f444121336a521a293fa61" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/42a4aa23b48b4cfc8ebfeac2b570364e27744381", - "reference": "42a4aa23b48b4cfc8ebfeac2b570364e27744381", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/40f9cf38c05296bd32f444121336a521a293fa61", + "reference": "40f9cf38c05296bd32f444121336a521a293fa61", "shasum": "" }, "require": { "php": "^7.2|^8.0", - "phpstan/phpstan": "^1.11.11" + "phpstan/phpstan": "^1.12.5" }, "conflict": { "rector/rector-doctrine": "*", @@ -3843,7 +3838,7 @@ ], "support": { "issues": "https://github.com/rectorphp/rector/issues", - "source": "https://github.com/rectorphp/rector/tree/1.2.4" + "source": "https://github.com/rectorphp/rector/tree/1.2.10" }, "funding": [ { @@ -3851,7 +3846,7 @@ "type": "github" } ], - "time": "2024-08-23T09:03:01+00:00" + "time": "2024-11-08T13:59:10+00:00" }, { "name": "revolt/event-loop", @@ -5878,28 +5873,28 @@ }, { "name": "webmozart/assert", - "version": "1.11.0", + "version": "1.12.0", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + "reference": "541057574806f942c94662b817a50f63f7345360" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/541057574806f942c94662b817a50f63f7345360", + "reference": "541057574806f942c94662b817a50f63f7345360", "shasum": "" }, "require": { "ext-ctype": "*", + "ext-date": "*", + "ext-filter": "*", "php": "^7.2 || ^8.0" }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" + "suggest": { + "ext-intl": "", + "ext-simplexml": "", + "ext-spl": "" }, "type": "library", "extra": { @@ -5930,9 +5925,9 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.11.0" + "source": "https://github.com/webmozarts/assert/tree/1.12.0" }, - "time": "2022-06-03T18:03:27+00:00" + "time": "2025-10-20T12:43:39+00:00" } ], "aliases": [], From 2bf491b214c6a0b6bd77fe24b161f86c94dac345 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 28 Oct 2025 09:13:00 +0000 Subject: [PATCH 032/158] wip --- tests/Browser/PluginSettingsTest.php | 6 +++++- tests/Pest.php | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 31c48e8..9142be8 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -1,5 +1,9 @@ '; + test('Sign in', function () { $page = visit('http://127.0.0.1:8100/wp-admin'); @@ -9,5 +13,5 @@ $page->assertSee('Welcome to WordPress!'); $page2 = visit('http://127.0.0.1:8100')->screenshot(); - expect($page2->content())->toContain(''); + expect($page2->content())->not->toContain(DEFAULT_SA_NOTICE); }); diff --git a/tests/Pest.php b/tests/Pest.php index b239048..7d18a9b 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -1,5 +1,7 @@ extend(Tests\TestCase::class)->in('Feature'); +pest()->extend(TestCase::class)->in('Feature'); /* |-------------------------------------------------------------------------- From 75ca7d5e9c82a39e184811985adf7c0f978f8a45 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 28 Oct 2025 09:15:46 +0000 Subject: [PATCH 033/158] wip --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index eb1eda5..b8559b6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -75,7 +75,7 @@ jobs: - name: Install WordPress run: | - rm wordpress/wp-config.php + rm -f wordpress/wp-config.php wp config create \ --dbname="$WP_DB_NAME" \ --dbuser="$WP_DB_USER" \ From 2e3f7a1c038ef0a31e078a2c2ac2392aa48c93fb Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 28 Oct 2025 11:23:57 +0000 Subject: [PATCH 034/158] wip --- tests/Browser/PluginSettingsTest.php | 14 +++++++------- tests/Pest.php | 11 +++++++++-- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 9142be8..ab326db 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -2,16 +2,16 @@ namespace Tests\Browser; +use function Tests\asAdmin; + const DEFAULT_SA_NOTICE = ''; -test('Sign in', function () { - $page = visit('http://127.0.0.1:8100/wp-admin'); +test('Sign in as admin and activate the plugin', function () { + $page = asAdmin(); - $page->fill('user_login', 'admin'); - $page->fill('user_pass', 'admin'); - $page->press('wp-submit'); - $page->assertSee('Welcome to WordPress!'); + $page->navigate('http://localhost:8100/wp-admin/plugins.php')->screenshot(); + $page->assertSee('Simple Analytics Official'); - $page2 = visit('http://127.0.0.1:8100')->screenshot(); + $page2 = visit('http://127.0.0.1:8100');//->screenshot(); expect($page2->content())->not->toContain(DEFAULT_SA_NOTICE); }); diff --git a/tests/Pest.php b/tests/Pest.php index 7d18a9b..3e3b08a 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -41,7 +41,14 @@ | */ -function something() +function asAdmin() { - // .. + $page = visit('http://127.0.0.1:8100/wp-admin'); + + $page->fill('user_login', 'admin'); + $page->fill('user_pass', 'admin'); + $page->press('wp-submit'); + $page->assertSee('Welcome to WordPress!'); + + return $page; } From 55cf64da291fb6bafbff3e92979d6d10834e72b9 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 28 Oct 2025 11:32:55 +0000 Subject: [PATCH 035/158] wip --- tests/Pest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Pest.php b/tests/Pest.php index 3e3b08a..dc22b33 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -48,7 +48,7 @@ function asAdmin() $page->fill('user_login', 'admin'); $page->fill('user_pass', 'admin'); $page->press('wp-submit'); - $page->assertSee('Welcome to WordPress!'); + $page->assertUrlIs('http://127.0.0.1:8100/wp-admin'); return $page; } From 3f3f5b747070e2a9837ad6cee0d0c2533b2b026e Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 28 Oct 2025 11:36:03 +0000 Subject: [PATCH 036/158] wip --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b8559b6..1857a9d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -36,7 +36,7 @@ jobs: env: WP_VERSION: ${{ matrix.wordpress }} - WP_SITE_URL: http://localhost:8100 + WP_SITE_URL: http://127.0.0.1:8100 WP_DB_NAME: wordpress WP_DB_USER: root WP_DB_PASS: root From a86a7cbbb018169171e4e83d5ea605efb7569448 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 28 Oct 2025 11:39:53 +0000 Subject: [PATCH 037/158] wip --- .github/workflows/tests.yml | 2 +- tests/Browser/PluginSettingsTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1857a9d..aa998ad 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -64,7 +64,7 @@ jobs: uses: actions/cache@v3 with: path: wordpress - key: wp-${{ matrix.wordpress }}-php-${{ matrix.php }} + key: wp-${{ matrix.wordpress }} - name: Download WordPress if: steps.cache-wordpress.outputs.cache-hit != 'true' diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index ab326db..2d83481 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -9,7 +9,7 @@ test('Sign in as admin and activate the plugin', function () { $page = asAdmin(); - $page->navigate('http://localhost:8100/wp-admin/plugins.php')->screenshot(); + $page->navigate('http://127.0.0.1:8100/wp-admin/plugins.php')->screenshot(); $page->assertSee('Simple Analytics Official'); $page2 = visit('http://127.0.0.1:8100');//->screenshot(); From baf678c43cbafab4489e1026f7838c17a42cde62 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Thu, 30 Oct 2025 10:50:10 +0000 Subject: [PATCH 038/158] wip --- .github/workflows/tests.yml | 4 ++-- tests/Browser/PluginSettingsTest.php | 25 ++++++++++++++++++------- tests/Pest.php | 13 +++++-------- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index aa998ad..1e1cc76 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -36,7 +36,7 @@ jobs: env: WP_VERSION: ${{ matrix.wordpress }} - WP_SITE_URL: http://127.0.0.1:8100 + WP_SITE_URL: http://localhost:8100 WP_DB_NAME: wordpress WP_DB_USER: root WP_DB_PASS: root @@ -104,7 +104,7 @@ jobs: - name: Start PHP server run: | - php -S 127.0.0.1:8100 -t wordpress > /dev/null 2>&1 & until curl -sSf http://127.0.0.1:8100 > /dev/null; do sleep 0.2; done + php -S localhost:8100 -t wordpress > /dev/null 2>&1 & until curl -sSf http://localhost:8100 > /dev/null; do sleep 0.2; done - name: Install pnpm uses: pnpm/action-setup@v4 diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 2d83481..2eeb9fb 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -4,14 +4,25 @@ use function Tests\asAdmin; -const DEFAULT_SA_NOTICE = ''; +const SA_ADMIN_NOTICE = ''; +const SA_DEFAULT_SCRIPT = ''; +const WP_PLUGIN_ROW_SELECTOR = 'tr[data-slug="simpleanalytics"]'; +const WP_ACTIVATE_PLUGIN_SELECTOR = '#activate-simpleanalytics'; -test('Sign in as admin and activate the plugin', function () { - $page = asAdmin(); +it('can be activated', function () { + asAdmin() + ->navigate('http://localhost:8100/wp-admin/plugins.php') + ->assertPresent(WP_PLUGIN_ROW_SELECTOR) + ->click(WP_ACTIVATE_PLUGIN_SELECTOR); +}); - $page->navigate('http://127.0.0.1:8100/wp-admin/plugins.php')->screenshot(); - $page->assertSee('Simple Analytics Official'); +it('adds a script by default', function () { + $homePage = visit('http://localhost:8100'); + expect($homePage->content())->toContain(SA_DEFAULT_SCRIPT); +}); - $page2 = visit('http://127.0.0.1:8100');//->screenshot(); - expect($page2->content())->not->toContain(DEFAULT_SA_NOTICE); +it('adds a comment when an authenticated user visits', function () { + $homePage = asAdmin()->navigate('http://localhost:8100'); + expect($homePage->content())->toContain(SA_ADMIN_NOTICE); + $homePage->assertNoConsoleLogs(); }); diff --git a/tests/Pest.php b/tests/Pest.php index dc22b33..cf4419d 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -43,12 +43,9 @@ function asAdmin() { - $page = visit('http://127.0.0.1:8100/wp-admin'); - - $page->fill('user_login', 'admin'); - $page->fill('user_pass', 'admin'); - $page->press('wp-submit'); - $page->assertUrlIs('http://127.0.0.1:8100/wp-admin'); - - return $page; + return visit('http://localhost:8100/wp-admin') + ->fill('user_login', 'admin') + ->fill('user_pass', 'admin') + ->press('wp-submit') + ->assertUrlIs('http://localhost:8100/wp-admin'); } From 448c03917647296a0deba192ff8205b0d51fedb6 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Thu, 30 Oct 2025 15:47:35 +0000 Subject: [PATCH 039/158] wip --- .github/workflows/tests.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1e1cc76..0a64073 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -100,7 +100,6 @@ jobs: run: | PLUGIN_SLUG=$(basename "$GITHUB_WORKSPACE") ln -s "$GITHUB_WORKSPACE" "wordpress/wp-content/plugins/simpleanalytics" - wp plugin activate simpleanalytics --path=wordpress --allow-root - name: Start PHP server run: | From 3f6db8a8e5cb7435edcb610eaeda466bfcf8d74d Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Thu, 30 Oct 2025 18:12:22 +0000 Subject: [PATCH 040/158] wip --- tests/Browser/PluginSettingsTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 2eeb9fb..8842d61 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -12,6 +12,7 @@ it('can be activated', function () { asAdmin() ->navigate('http://localhost:8100/wp-admin/plugins.php') + ->screenshot() ->assertPresent(WP_PLUGIN_ROW_SELECTOR) ->click(WP_ACTIVATE_PLUGIN_SELECTOR); }); From 59ed5b68e71d81950e9c0a541266279ff3cc6bfe Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 09:32:45 +0000 Subject: [PATCH 041/158] wip --- tests/Browser/PluginSettingsTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 8842d61..764cee8 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -19,11 +19,11 @@ it('adds a script by default', function () { $homePage = visit('http://localhost:8100'); - expect($homePage->content())->toContain(SA_DEFAULT_SCRIPT); + expect($homePage->content())->toContain(SA_DEFAULT_SCRIPT)->dump(); }); it('adds a comment when an authenticated user visits', function () { $homePage = asAdmin()->navigate('http://localhost:8100'); - expect($homePage->content())->toContain(SA_ADMIN_NOTICE); + expect($homePage->content())->toContain(SA_ADMIN_NOTICE)->dump(); $homePage->assertNoConsoleLogs(); }); From cc71bd071ff5a2e5558e14e407fd01e95ab59010 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 09:38:22 +0000 Subject: [PATCH 042/158] wip --- tests/Browser/PluginSettingsTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 764cee8..5ccc8f9 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -19,11 +19,11 @@ it('adds a script by default', function () { $homePage = visit('http://localhost:8100'); - expect($homePage->content())->toContain(SA_DEFAULT_SCRIPT)->dump(); + expect($homePage->content())->dump()->toContain(SA_DEFAULT_SCRIPT); }); it('adds a comment when an authenticated user visits', function () { $homePage = asAdmin()->navigate('http://localhost:8100'); - expect($homePage->content())->toContain(SA_ADMIN_NOTICE)->dump(); + expect($homePage->content())->dump()->toContain(SA_ADMIN_NOTICE); $homePage->assertNoConsoleLogs(); }); From 797144f22ccb91611f9bcf5e8d9310d9ab0933dc Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 09:41:17 +0000 Subject: [PATCH 043/158] wip --- tests/Browser/PluginSettingsTest.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 5ccc8f9..0a96b67 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -8,13 +8,17 @@ const SA_DEFAULT_SCRIPT = ''; const WP_PLUGIN_ROW_SELECTOR = 'tr[data-slug="simpleanalytics"]'; const WP_ACTIVATE_PLUGIN_SELECTOR = '#activate-simpleanalytics'; +const WP_DEACTIVATE_PLUGIN_SELECTOR = '#deactivate-simpleanalytics'; +const WP_PLUGIN_MENU_ITEM = 'a[href="options-general.php?page=simpleanalytics"]'; it('can be activated', function () { asAdmin() ->navigate('http://localhost:8100/wp-admin/plugins.php') ->screenshot() ->assertPresent(WP_PLUGIN_ROW_SELECTOR) - ->click(WP_ACTIVATE_PLUGIN_SELECTOR); + ->click(WP_ACTIVATE_PLUGIN_SELECTOR) + ->assertPresent(WP_PLUGIN_MENU_ITEM) + ->assertPresent(WP_DEACTIVATE_PLUGIN_SELECTOR); }); it('adds a script by default', function () { From 13736fd4caf38c4006b379d65797995077c2755e Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 09:44:18 +0000 Subject: [PATCH 044/158] wip --- .github/workflows/tests.yml | 3 +-- tests/Feature/ExampleTest.php | 5 ----- tests/Unit/ExampleTest.php | 5 ----- 3 files changed, 1 insertion(+), 12 deletions(-) delete mode 100644 tests/Feature/ExampleTest.php delete mode 100644 tests/Unit/ExampleTest.php diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0a64073..05af5ed 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -56,8 +56,7 @@ jobs: - name: Install dependencies run: | - sudo apt-get update - sudo apt-get install -y unzip curl jq + sudo apt-get install -y unzip - name: Cache WordPress archive id: cache-wordpress diff --git a/tests/Feature/ExampleTest.php b/tests/Feature/ExampleTest.php deleted file mode 100644 index 61cd84c..0000000 --- a/tests/Feature/ExampleTest.php +++ /dev/null @@ -1,5 +0,0 @@ -toBeTrue(); -}); diff --git a/tests/Unit/ExampleTest.php b/tests/Unit/ExampleTest.php deleted file mode 100644 index 61cd84c..0000000 --- a/tests/Unit/ExampleTest.php +++ /dev/null @@ -1,5 +0,0 @@ -toBeTrue(); -}); From 9b3031f487dbe8bb559f445985ed50d84ee858a4 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 09:45:31 +0000 Subject: [PATCH 045/158] wip --- .github/workflows/tests.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 05af5ed..c594c1a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -54,10 +54,6 @@ jobs: coverage: none tools: wp-cli - - name: Install dependencies - run: | - sudo apt-get install -y unzip - - name: Cache WordPress archive id: cache-wordpress uses: actions/cache@v3 From 9736c9b5bcfe58e1ea12c92c09643c0e550627ae Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 09:48:37 +0000 Subject: [PATCH 046/158] chromium only --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 36605e0..10a94a1 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "scripts": { "dev": "tailwindcss -i resources/css/settings.css -o build/css/settings.css --watch", "build": "tailwindcss build -i resources/css/settings.css -o build/css/settings.css", - "tests:install": "playwright install --with-deps", + "tests:install": "playwright install --with-deps chromium", "tests": "playwright test" }, "devDependencies": { From 17e3f7ba6483e0c054dc84f795bdb9757494e386 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 10:06:04 +0000 Subject: [PATCH 047/158] wip --- tests/Browser/PluginSettingsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 0a96b67..ee0ebdd 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -5,7 +5,7 @@ use function Tests\asAdmin; const SA_ADMIN_NOTICE = ''; -const SA_DEFAULT_SCRIPT = ''; +const SA_DEFAULT_SCRIPT = 'src="https://scripts.simpleanalyticscdn.com/latest.js">'; const WP_PLUGIN_ROW_SELECTOR = 'tr[data-slug="simpleanalytics"]'; const WP_ACTIVATE_PLUGIN_SELECTOR = '#activate-simpleanalytics'; const WP_DEACTIVATE_PLUGIN_SELECTOR = '#deactivate-simpleanalytics'; From 504d66ffdf13f2468744f5f1d41053133d5a1ff5 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 10:39:42 +0000 Subject: [PATCH 048/158] wip --- simple-analytics.php | 2 +- src/Plugin.php | 16 ++++++---- .../Concerns/WordPressPageIntegration.php | 3 ++ src/TrackingPolicy.php | 29 ------------------- src/TrackingRules.php | 24 +++++++++++++++ 5 files changed, 38 insertions(+), 36 deletions(-) delete mode 100644 src/TrackingPolicy.php create mode 100644 src/TrackingRules.php diff --git a/simple-analytics.php b/simple-analytics.php index 719e178..c8f4eb5 100644 --- a/simple-analytics.php +++ b/simple-analytics.php @@ -33,7 +33,7 @@ require __DIR__ . '/src/Plugin.php'; require __DIR__ . '/src/Setting.php'; require __DIR__ . '/src/SettingName.php'; -require __DIR__ . '/src/TrackingPolicy.php'; +require __DIR__ . '/src/TrackingRules.php'; require __DIR__ . '/src/ScriptManager.php'; require __DIR__ . '/src/Scripts/Contracts/Script.php'; require __DIR__ . '/src/Scripts/Contracts/HideScriptId.php'; diff --git a/src/Plugin.php b/src/Plugin.php index 6627663..118a595 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -34,14 +34,18 @@ public function onUninstall(): void public function onInit(): void { - $shouldCollect = (new TrackingPolicy)->shouldCollectAnalytics(); - $this->addScripts($shouldCollect); - if (! $shouldCollect) { - AddInactiveComment::register(); - } - if ($shouldCollect && Setting::boolean(SettingName::NOSCRIPT)) { + $rules = new TrackingRules(); + $tracking = $rules->excludedIp(); + + $this->addScripts($tracking); + + if ($tracking && Setting::boolean(SettingName::NOSCRIPT)) { AddNoScriptTag::register(); } + + if (! $rules->excludedUserRole()) { + AddInactiveComment::register(); + } } /** diff --git a/src/Settings/Concerns/WordPressPageIntegration.php b/src/Settings/Concerns/WordPressPageIntegration.php index b50699f..391d7a1 100644 --- a/src/Settings/Concerns/WordPressPageIntegration.php +++ b/src/Settings/Concerns/WordPressPageIntegration.php @@ -8,6 +8,9 @@ trait WordPressPageIntegration { + /** @return Tab[] */ + abstract function getTabs(): array; + public function register(): void { add_action('admin_menu', [$this, 'wpAddMenu']); diff --git a/src/TrackingPolicy.php b/src/TrackingPolicy.php deleted file mode 100644 index babf70a..0000000 --- a/src/TrackingPolicy.php +++ /dev/null @@ -1,29 +0,0 @@ -clientIpExcluded($_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'])) { - return false; - } - - if (! is_user_logged_in()) { - return true; - } - - return ! $this->containsExcludedRole(wp_get_current_user()->roles); - } - - protected function clientIpExcluded(string $ip): bool - { - return in_array($ip, Setting::array(SettingName::EXCLUDED_IP_ADDRESSES)); - } - - protected function containsExcludedRole(array $roles): bool - { - return array_intersect(Setting::array(SettingName::EXCLUDED_ROLES), $roles) !== []; - } -} diff --git a/src/TrackingRules.php b/src/TrackingRules.php new file mode 100644 index 0000000..bb0a9fa --- /dev/null +++ b/src/TrackingRules.php @@ -0,0 +1,24 @@ +roles; + + return array_intersect($needle, $current) !== []; + } +} From d2138ad8ba304b4751101bc73a6ea6b7d3118617 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 12:02:19 +0000 Subject: [PATCH 049/158] Refactor --- simple-analytics.php | 110 +++++++++- src/Plugin.php | 196 ++++-------------- src/PluginLifecycle.php | 26 --- src/{ScriptManager.php => ScriptRegistry.php} | 10 +- src/Settings/{Page.php => AdminPage.php} | 2 +- src/TrackingRules.php | 15 +- src/UI/PageLayoutComponent.php | 6 +- src/WordPressHooks.php | 26 +++ src/WordPressSettings.php | 54 +++++ 9 files changed, 251 insertions(+), 194 deletions(-) delete mode 100644 src/PluginLifecycle.php rename src/{ScriptManager.php => ScriptRegistry.php} (91%) rename src/Settings/{Page.php => AdminPage.php} (98%) create mode 100644 src/WordPressHooks.php create mode 100644 src/WordPressSettings.php diff --git a/simple-analytics.php b/simple-analytics.php index c8f4eb5..267f4d7 100644 --- a/simple-analytics.php +++ b/simple-analytics.php @@ -29,12 +29,13 @@ */ require __DIR__ . '/src/Support/SvgIcon.php'; require __DIR__ . '/helpers.php'; -require __DIR__ . '/src/PluginLifecycle.php'; require __DIR__ . '/src/Plugin.php'; +require __DIR__ . '/src/WordPressHooks.php'; +require __DIR__ . '/src/WordPressSettings.php'; require __DIR__ . '/src/Setting.php'; require __DIR__ . '/src/SettingName.php'; require __DIR__ . '/src/TrackingRules.php'; -require __DIR__ . '/src/ScriptManager.php'; +require __DIR__ . '/src/ScriptRegistry.php'; require __DIR__ . '/src/Scripts/Contracts/Script.php'; require __DIR__ . '/src/Scripts/Contracts/HideScriptId.php'; require __DIR__ . '/src/Scripts/Contracts/HasAttributes.php'; @@ -52,7 +53,7 @@ require __DIR__ . '/src/Settings/Concerns/HasPlaceholder.php'; require __DIR__ . '/src/Settings/Concerns/ManagesBlocks.php'; require __DIR__ . '/src/Settings/Concerns/WordPressPageIntegration.php'; -require __DIR__ . '/src/Settings/Page.php'; +require __DIR__ . '/src/Settings/AdminPage.php'; require __DIR__ . '/src/Settings/Blocks/Fields/Field.php'; require __DIR__ . '/src/Settings/Blocks/Fields/Input.php'; require __DIR__ . '/src/Settings/Blocks/Fields/Checkboxes.php'; @@ -63,6 +64,105 @@ require __DIR__ . '/src/UI/TabListComponent.php'; require __DIR__ . '/src/UI/PageLayoutComponent.php'; -use SimpleAnalytics\Plugin; +use SimpleAnalytics\SettingName; +use SimpleAnalytics\Settings\Tab; +use function SimpleAnalytics\get_icon; -(new Plugin)->boot(); +$settings = new SimpleAnalytics\WordPressSettings(); +$hooks = new SimpleAnalytics\WordPressHooks(); +$rules = new SimpleAnalytics\TrackingRules($settings); +$scripts = new SimpleAnalytics\ScriptRegistry(/*TODO TAKE $hooks WordPressHooks as arg/dependency*/); + +$adminPage = SimpleAnalytics\Settings\AdminPage::title('Simple Analytics') + ->slug('simpleanalytics') + ->tab('General', function (Tab $tab) { + $tab->input(SettingName::CUSTOM_DOMAIN, 'Custom Domain') + ->placeholder('Enter your custom domain or leave it empty.') + ->description('E.g. api.example.com. Leave empty to use the default domain (most users).') + ->docs('https://docs.simpleanalytics.com/bypass-ad-blockers'); + }) + ->tab('Ignore Rules', function (Tab $tab) { + $tab->icon(get_icon('eye-slash')); + + $tab->input(SettingName::IGNORE_PAGES, 'Ignore Pages') + ->description('Comma separated list of pages to ignore. E.g. /contact, /about') + ->placeholder('Example: /page1, /page2, /category/*') + ->docs('https://docs.simpleanalytics.com/ignore-pages'); + + $tab->callout('IP and role exclusion only works when there is no page caching.'); + + $tab->multiCheckbox(SettingName::EXCLUDED_ROLES, 'Exclude User Roles') + ->options(function () { + return wp_roles()->get_names(); + }); + + $tab->ipList(SettingName::EXCLUDED_IP_ADDRESSES, 'Exclude IP Addresses') + ->placeholder("127.0.0.1\n192.168.0.1") + ->description('IP addresses to exclude from tracking.'); + }) + ->tab('Advanced', function (Tab $tab) { + $tab->icon(get_icon('cog')); + + $tab->checkbox(SettingName::COLLECT_DNT, 'Collect Do Not Track') + ->description('If you want to collect visitors with Do Not Track enabled, turn this on.') + ->docs('https://docs.simpleanalytics.com/dnt'); + + $tab->checkbox(SettingName::HASH_MODE, 'Hash mode') + ->description('If your website uses hash (#) navigation, turn this on. On most WordPress websites this is not relevant.') + ->docs('https://docs.simpleanalytics.com/hash-mode'); + + $tab->checkbox(SettingName::MANUAL_COLLECT, 'Manually collect page views') + ->description('In case you don’t want to auto collect page views, but via `sa_pageview` function in JavaScript.') + ->docs('https://docs.simpleanalytics.com/trigger-custom-page-views#use-custom-collection-anyway'); + + $tab->checkbox(SettingName::NOSCRIPT, 'Support no JavaScript mode') + ->description('Collect analytics from visitors with disabled or no JavaScript.'); + + $tab->input(SettingName::ONLOAD_CALLBACK, 'Onload Callback') + ->description('JavaScript function to call when the script is loaded.') + ->placeholder('Example: sa_event("My event")') + ->docs('https://docs.simpleanalytics.com/trigger-custom-page-views#use-custom-collection-anyway'); + + $tab->input(SettingName::HOSTNAME, 'Overwrite domain name') + ->description('Override the domain that is sent to Simple Analytics. Useful for multi-domain setups.') + ->placeholder('Example: example.com') + ->docs('https://docs.simpleanalytics.com/overwrite-domain-name'); + + $tab->input(SettingName::SA_GLOBAL, 'Global variable name') + ->description('Change the global variable name of Simple Analytics. Default is `sa_event`.') + ->placeholder('Example: ba_event') + ->docs('https://docs.simpleanalytics.com/events#the-variable-sa_event-is-already-used'); + }) + ->tab('Events', function (Tab $tab) { + $tab->title('Automated events') + ->icon(get_icon('events')) + ->description("It will track outbound links, email addresses clicks, + and amount of downloads for common files (pdf, csv, docx, xIsx). + Events will appear on your events page on simpleanalytics.com"); + + $tab->checkbox(SettingName::AUTOMATED_EVENTS, 'Collect automated events'); + + $tab->input(SettingName::EVENT_COLLECT_DOWNLOADS, 'Auto collect downloads') + ->placeholder('Example: outbound,emails,downloads') + ->docs('https://docs.simpleanalytics.com/automated-events'); + + $tab->input(SettingName::EVENT_EXTENSIONS, 'Download file extensions') + ->description('Comma separated list of file extensions to track as downloads. E.g. pdf, zip') + ->placeholder('Example: pdf, zip') + ->docs('https://docs.simpleanalytics.com/automated-events'); + + $tab->checkbox(SettingName::EVENT_USE_TITLE, 'Use titles of page') + ->description('Use the title of the page as the event name. Default is the URL.') + ->docs('https://docs.simpleanalytics.com/automated-events'); + + $tab->checkbox(SettingName::EVENT_FULL_URLS, 'Use full URLs') + ->description('Use full URLs instead of the path. Default is the path.') + ->docs('https://docs.simpleanalytics.com/automated-events'); + + $tab->input(SettingName::EVENT_SA_GLOBAL, 'Override global') + ->description('Override the global variable name of Simple Analytics. Default is `sa_event`.') + ->placeholder('Example: ba_event') + ->docs('https://docs.simpleanalytics.com/events#the-variable-sa_event-is-already-used'); + }); + +(new SimpleAnalytics\Plugin($hooks, $settings, $rules, $scripts, $adminPage))->boot(); diff --git a/src/Plugin.php b/src/Plugin.php index 118a595..967cddd 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -2,191 +2,87 @@ namespace SimpleAnalytics; -use SimpleAnalytics\Settings\{Page, Tab}; use SimpleAnalytics\Actions\AddInactiveComment; use SimpleAnalytics\Actions\AddNoScriptTag; use SimpleAnalytics\Actions\AddPluginSettingsLink; use SimpleAnalytics\Scripts\AnalyticsScript; use SimpleAnalytics\Scripts\AutomatedEventsScript; use SimpleAnalytics\Scripts\InactiveScript; +use SimpleAnalytics\Settings\AdminPage; final class Plugin { - use PluginLifecycle; - - protected function onBoot(): void - { - if (is_admin()) { - $this->defineAdminPage(); - AddPluginSettingsLink::register(); - } + protected $hooks; + protected $settings; + protected $trackingRules; + protected $scripts; + protected $adminPage; + + public function __construct( + WordPressHooks $hooks, + WordPressSettings $settings, + TrackingRules $trackingRules, + ScriptRegistry $scripts, + AdminPage $adminPage + ) { + $this->hooks = $hooks; + $this->settings = $settings; + $this->trackingRules = $trackingRules; + $this->scripts = $scripts; + $this->adminPage = $adminPage; } - public function onActivation(): void + public function boot(): void { - $this->addOptions(); - } + $this->hooks->addAction('init', \Closure::fromCallable([$this, 'onInit'])); + $this->hooks->onActivation(\Closure::fromCallable([$this, 'onActivation'])); + $this->hooks->onDeactivation(\Closure::fromCallable([$this, 'onUninstall'])); - public function onUninstall(): void - { - $this->deleteOptions(); + if ($this->hooks->isAdmin()) { + $this->adminPage->register(); + AddPluginSettingsLink::register(); + } } public function onInit(): void { - $rules = new TrackingRules(); - $tracking = $rules->excludedIp(); - - $this->addScripts($tracking); + $tracking = $this->trackingRules->hasExcludedIp(); - if ($tracking && Setting::boolean(SettingName::NOSCRIPT)) { + if ($tracking && $this->settings->get(SettingName::NOSCRIPT)) { AddNoScriptTag::register(); } - if (! $rules->excludedUserRole()) { + if (! $this->trackingRules->hasExcludedUserRole()) { AddInactiveComment::register(); } - } - /** - * Register plugin options and autoload them. - * - * @note Eliminates any unnecessary database lookups by preloading on each request. - * @note Thanks to option autoloading, we don't need to use one serialized option, but several. - * This allows the usage of native hooks and filters and reduces the chance of data corruption. - */ - protected function addOptions(): void - { - // Add options with default values - add_option(SettingName::ENABLED, '1', null, true); - - // Add all remaining options - $optionNames = array_diff(SettingName::cases(), [SettingName::ENABLED]); - foreach ($optionNames as $name) { - add_option($name, null, null, true); + if ($tracking) { + $this->scripts->push(new AnalyticsScript); + } else { + $this->scripts->push(new InactiveScript); } - // Legacy. Update the option introduced in a previous release to use autoloading. - update_option(SettingName::CUSTOM_DOMAIN, get_option(SettingName::CUSTOM_DOMAIN), true); - } - - protected function deleteOptions(): void - { - foreach (SettingName::cases() as $name) { - delete_option($name); + if ($this->settings->boolean(SettingName::AUTOMATED_EVENTS)) { + $this->scripts->push(new AutomatedEventsScript); } + + $this->scripts->register(); } - protected function addScripts(bool $collect): void + public function onActivation(): void { - $scripts = new ScriptManager; - - if ($collect) { - $scripts->add(new AnalyticsScript); - } elseif (is_user_logged_in()) { - $scripts->add(new InactiveScript); - } + $this->settings->register(SettingName::ENABLED, true); - if (Setting::boolean(SettingName::AUTOMATED_EVENTS)) { - $scripts->add(new AutomatedEventsScript); + foreach (array_diff(SettingName::cases(), [SettingName::ENABLED]) as $name) { + $this->settings->register($name); } - $scripts->register(); + // Legacy. Update the option introduced in a previous release to use autoloading. + $this->settings->update(SettingName::CUSTOM_DOMAIN, $this->settings->get(SettingName::CUSTOM_DOMAIN), true); } - protected function defineAdminPage(): void + public function onUninstall(): void { - Page::title('Simple Analytics') - ->slug('simpleanalytics') - ->tab('General', function (Tab $tab) { - $tab->input(SettingName::CUSTOM_DOMAIN, 'Custom Domain') - ->placeholder('Enter your custom domain or leave it empty.') - ->description('E.g. api.example.com. Leave empty to use the default domain (most users).') - ->docs('https://docs.simpleanalytics.com/bypass-ad-blockers'); - }) - ->tab('Ignore Rules', function (Tab $tab) { - $tab->icon(get_icon('eye-slash')); - - $tab->input(SettingName::IGNORE_PAGES, 'Ignore Pages') - ->description('Comma separated list of pages to ignore. E.g. /contact, /about') - ->placeholder('Example: /page1, /page2, /category/*') - ->docs('https://docs.simpleanalytics.com/ignore-pages'); - - $tab->callout('IP and role exclusion only works when there is no page caching.'); - - $tab->multiCheckbox(SettingName::EXCLUDED_ROLES, 'Exclude User Roles') - ->options(function () { - return wp_roles()->get_names(); - }); - - $tab->ipList(SettingName::EXCLUDED_IP_ADDRESSES, 'Exclude IP Addresses') - ->placeholder("127.0.0.1\n192.168.0.1") - ->description('IP addresses to exclude from tracking.'); - }) - ->tab('Advanced', function (Tab $tab) { - $tab->icon(get_icon('cog')); - - $tab->checkbox(SettingName::COLLECT_DNT, 'Collect Do Not Track') - ->description('If you want to collect visitors with Do Not Track enabled, turn this on.') - ->docs('https://docs.simpleanalytics.com/dnt'); - - $tab->checkbox(SettingName::HASH_MODE, 'Hash mode') - ->description('If your website uses hash (#) navigation, turn this on. On most WordPress websites this is not relevant.') - ->docs('https://docs.simpleanalytics.com/hash-mode'); - - $tab->checkbox(SettingName::MANUAL_COLLECT, 'Manually collect page views') - ->description('In case you don’t want to auto collect page views, but via `sa_pageview` function in JavaScript.') - ->docs('https://docs.simpleanalytics.com/trigger-custom-page-views#use-custom-collection-anyway'); - - $tab->checkbox(SettingName::NOSCRIPT, 'Support no JavaScript mode') - ->description('Collect analytics from visitors with disabled or no JavaScript.'); - - $tab->input(SettingName::ONLOAD_CALLBACK, 'Onload Callback') - ->description('JavaScript function to call when the script is loaded.') - ->placeholder('Example: sa_event("My event")') - ->docs('https://docs.simpleanalytics.com/trigger-custom-page-views#use-custom-collection-anyway'); - - $tab->input(SettingName::HOSTNAME, 'Overwrite domain name') - ->description('Override the domain that is sent to Simple Analytics. Useful for multi-domain setups.') - ->placeholder('Example: example.com') - ->docs('https://docs.simpleanalytics.com/overwrite-domain-name'); - - $tab->input(SettingName::SA_GLOBAL, 'Global variable name') - ->description('Change the global variable name of Simple Analytics. Default is `sa_event`.') - ->placeholder('Example: ba_event') - ->docs('https://docs.simpleanalytics.com/events#the-variable-sa_event-is-already-used'); - }) - ->tab('Events', function (Tab $tab) { - $tab->title('Automated events') - ->icon(get_icon('events')) - ->description("It will track outbound links, email addresses clicks, - and amount of downloads for common files (pdf, csv, docx, xIsx). - Events will appear on your events page on simpleanalytics.com"); - - $tab->checkbox(SettingName::AUTOMATED_EVENTS, 'Collect automated events'); - - $tab->input(SettingName::EVENT_COLLECT_DOWNLOADS, 'Auto collect downloads') - ->placeholder('Example: outbound,emails,downloads') - ->docs('https://docs.simpleanalytics.com/automated-events'); - - $tab->input(SettingName::EVENT_EXTENSIONS, 'Download file extensions') - ->description('Comma separated list of file extensions to track as downloads. E.g. pdf, zip') - ->placeholder('Example: pdf, zip') - ->docs('https://docs.simpleanalytics.com/automated-events'); - - $tab->checkbox(SettingName::EVENT_USE_TITLE, 'Use titles of page') - ->description('Use the title of the page as the event name. Default is the URL.') - ->docs('https://docs.simpleanalytics.com/automated-events'); - - $tab->checkbox(SettingName::EVENT_FULL_URLS, 'Use full URLs') - ->description('Use full URLs instead of the path. Default is the path.') - ->docs('https://docs.simpleanalytics.com/automated-events'); - - $tab->input(SettingName::EVENT_SA_GLOBAL, 'Override global') - ->description('Override the global variable name of Simple Analytics. Default is `sa_event`.') - ->placeholder('Example: ba_event') - ->docs('https://docs.simpleanalytics.com/events#the-variable-sa_event-is-already-used'); - }) - ->register(); + foreach (SettingName::cases() as $key) $this->settings->delete($key); } } diff --git a/src/PluginLifecycle.php b/src/PluginLifecycle.php deleted file mode 100644 index b115877..0000000 --- a/src/PluginLifecycle.php +++ /dev/null @@ -1,26 +0,0 @@ -onBoot(); - add_action('init', \Closure::fromCallable([$this, 'onInit'])); - register_activation_hook(ENTRYPOINT_FILE, \Closure::fromCallable([$this, 'onActivation'])); - register_deactivation_hook(ENTRYPOINT_FILE, \Closure::fromCallable([$this, 'onUninstall'])); - } - - /** @internal */ - abstract protected function onBoot(): void; - - /** @internal */ - abstract public function onInit(): void; - - /** @internal */ - abstract public function onActivation(): void; - - /** @internal */ - abstract public function onUninstall(): void; -} diff --git a/src/ScriptManager.php b/src/ScriptRegistry.php similarity index 91% rename from src/ScriptManager.php rename to src/ScriptRegistry.php index 5eb8945..e79099f 100644 --- a/src/ScriptManager.php +++ b/src/ScriptRegistry.php @@ -9,16 +9,16 @@ /** * Register scripts with WordPress. */ -final class ScriptManager +final class ScriptRegistry { + /** @var Script[] */ private $scripts = []; - public function __construct($scripts = []) + + public function __construct() { - /** @var Script[] */ - $this->scripts = $scripts; } - public function add(Script $script): void + public function push(Script $script): void { $this->scripts[] = $script; } diff --git a/src/Settings/Page.php b/src/Settings/AdminPage.php similarity index 98% rename from src/Settings/Page.php rename to src/Settings/AdminPage.php index 88d5430..22c6058 100644 --- a/src/Settings/Page.php +++ b/src/Settings/AdminPage.php @@ -5,7 +5,7 @@ use SimpleAnalytics\Settings\Concerns\WordPressPageIntegration; use SimpleAnalytics\Support\Str; -class Page +class AdminPage { use WordPressPageIntegration; diff --git a/src/TrackingRules.php b/src/TrackingRules.php index bb0a9fa..c52dde1 100644 --- a/src/TrackingRules.php +++ b/src/TrackingRules.php @@ -4,19 +4,26 @@ class TrackingRules { - public function excludedIp(): bool + protected $settings; + + public function __construct(WordPressSettings $settings) + { + $this->settings = $settings; + } + + public function hasExcludedIp(): bool { $ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR']; - $list = Setting::array(SettingName::EXCLUDED_IP_ADDRESSES); + $list = $this->settings->array(SettingName::EXCLUDED_IP_ADDRESSES); return in_array($ip, $list); } - public function excludedUserRole(): bool + public function hasExcludedUserRole(): bool { if (! is_user_logged_in()) return false; - $needle = Setting::array(SettingName::EXCLUDED_ROLES); + $needle = $this->settings->array(SettingName::EXCLUDED_ROLES); $current = wp_get_current_user()->roles; return array_intersect($needle, $current) !== []; diff --git a/src/UI/PageLayoutComponent.php b/src/UI/PageLayoutComponent.php index 512940a..0a8d81c 100644 --- a/src/UI/PageLayoutComponent.php +++ b/src/UI/PageLayoutComponent.php @@ -2,7 +2,7 @@ namespace SimpleAnalytics\UI; -use SimpleAnalytics\Settings\{Page, Tab}; +use SimpleAnalytics\Settings\{AdminPage, Tab}; use function SimpleAnalytics\get_icon; use const SimpleAnalytics\PLUGIN_URL; @@ -10,10 +10,10 @@ class PageLayoutComponent { /** * @readonly - * @var \SimpleAnalytics\Settings\Page + * @var \SimpleAnalytics\Settings\AdminPage */ private $page; - public function __construct(Page $page) + public function __construct(AdminPage $page) { $this->page = $page; } diff --git a/src/WordPressHooks.php b/src/WordPressHooks.php new file mode 100644 index 0000000..c72529d --- /dev/null +++ b/src/WordPressHooks.php @@ -0,0 +1,26 @@ +get($key, []); + + return is_array($value) ? $value : [$value]; + } +} From 87918a3cf16c1fb6e22024ee691424f8817eb327 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 12:04:00 +0000 Subject: [PATCH 050/158] fix --- src/TrackingRules.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/TrackingRules.php b/src/TrackingRules.php index c52dde1..f71c629 100644 --- a/src/TrackingRules.php +++ b/src/TrackingRules.php @@ -14,6 +14,9 @@ public function __construct(WordPressSettings $settings) public function hasExcludedIp(): bool { $ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR']; + + if (empty($ip)) return false; + $list = $this->settings->array(SettingName::EXCLUDED_IP_ADDRESSES); return in_array($ip, $list); From abece7ce408d23aacf8b92cfd3754fe60268ebad Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 12:07:19 +0000 Subject: [PATCH 051/158] fix --- src/Plugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Plugin.php b/src/Plugin.php index 967cddd..d7761ad 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -46,7 +46,7 @@ public function boot(): void public function onInit(): void { - $tracking = $this->trackingRules->hasExcludedIp(); + $tracking = ! $this->trackingRules->hasExcludedIp(); if ($tracking && $this->settings->get(SettingName::NOSCRIPT)) { AddNoScriptTag::register(); From bc457099055f3ed364cde18f27e5a8803db445c3 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 12:14:16 +0000 Subject: [PATCH 052/158] wip --- src/Plugin.php | 5 +++-- tests/Browser/PluginSettingsTest.php | 8 ++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Plugin.php b/src/Plugin.php index d7761ad..923e082 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -47,16 +47,17 @@ public function boot(): void public function onInit(): void { $tracking = ! $this->trackingRules->hasExcludedIp(); + $excludedRole = $this->trackingRules->hasExcludedUserRole(); if ($tracking && $this->settings->get(SettingName::NOSCRIPT)) { AddNoScriptTag::register(); } - if (! $this->trackingRules->hasExcludedUserRole()) { + if (! $excludedRole) { AddInactiveComment::register(); } - if ($tracking) { + if ($tracking && ! $excludedRole) { $this->scripts->push(new AnalyticsScript); } else { $this->scripts->push(new InactiveScript); diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index ee0ebdd..df16c7e 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -6,6 +6,8 @@ const SA_ADMIN_NOTICE = ''; const SA_DEFAULT_SCRIPT = 'src="https://scripts.simpleanalyticscdn.com/latest.js">'; +const SA_INACTIVE_ADMIN_SCRIPT = 'resources/js/inactive.js">'; + const WP_PLUGIN_ROW_SELECTOR = 'tr[data-slug="simpleanalytics"]'; const WP_ACTIVATE_PLUGIN_SELECTOR = '#activate-simpleanalytics'; const WP_DEACTIVATE_PLUGIN_SELECTOR = '#deactivate-simpleanalytics'; @@ -28,6 +30,8 @@ it('adds a comment when an authenticated user visits', function () { $homePage = asAdmin()->navigate('http://localhost:8100'); - expect($homePage->content())->dump()->toContain(SA_ADMIN_NOTICE); - $homePage->assertNoConsoleLogs(); + + expect($homePage->content())->dump() + ->toContain(SA_ADMIN_NOTICE) + ->toContain(SA_INACTIVE_ADMIN_SCRIPT); }); From 509aab591b68f304e3d8484d20c98acb6096b488 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 12:15:42 +0000 Subject: [PATCH 053/158] wip --- src/Plugin.php | 7 +++---- tests/Browser/PluginSettingsTest.php | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Plugin.php b/src/Plugin.php index 923e082..8a1a08a 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -46,18 +46,17 @@ public function boot(): void public function onInit(): void { - $tracking = ! $this->trackingRules->hasExcludedIp(); - $excludedRole = $this->trackingRules->hasExcludedUserRole(); + $tracking = $this->trackingRules->hasExcludedIp() && $this->trackingRules->hasExcludedUserRole(); if ($tracking && $this->settings->get(SettingName::NOSCRIPT)) { AddNoScriptTag::register(); } - if (! $excludedRole) { + if (! $tracking) { AddInactiveComment::register(); } - if ($tracking && ! $excludedRole) { + if ($tracking) { $this->scripts->push(new AnalyticsScript); } else { $this->scripts->push(new InactiveScript); diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index df16c7e..2e06b0d 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -6,7 +6,7 @@ const SA_ADMIN_NOTICE = ''; const SA_DEFAULT_SCRIPT = 'src="https://scripts.simpleanalyticscdn.com/latest.js">'; -const SA_INACTIVE_ADMIN_SCRIPT = 'resources/js/inactive.js">'; +const SA_INACTIVE_ADMIN_SCRIPT = 'src="http://localhost:8100/wp-content/plugins/simpleanalytics/resources/js/inactive.js">'; const WP_PLUGIN_ROW_SELECTOR = 'tr[data-slug="simpleanalytics"]'; const WP_ACTIVATE_PLUGIN_SELECTOR = '#activate-simpleanalytics'; From d0b50539aea4722136b1fa16a0a6fab5caa9c157 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 12:20:03 +0000 Subject: [PATCH 054/158] clarify --- simple-analytics.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/simple-analytics.php b/simple-analytics.php index 267f4d7..27a5f28 100644 --- a/simple-analytics.php +++ b/simple-analytics.php @@ -91,7 +91,8 @@ $tab->callout('IP and role exclusion only works when there is no page caching.'); - $tab->multiCheckbox(SettingName::EXCLUDED_ROLES, 'Exclude User Roles') + $tab->multiCheckbox(SettingName::EXCLUDED_ROLES, 'Specific User Roles to Exclude') + ->description('When none selected, all authenticated users will be excluded from tracking.') ->options(function () { return wp_roles()->get_names(); }); From 78762950b6293f5a7c5c99acbed7b403b0d21f25 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 12:20:36 +0000 Subject: [PATCH 055/158] fix --- tests/Browser/PluginSettingsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 2e06b0d..3962d59 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -6,7 +6,7 @@ const SA_ADMIN_NOTICE = ''; const SA_DEFAULT_SCRIPT = 'src="https://scripts.simpleanalyticscdn.com/latest.js">'; -const SA_INACTIVE_ADMIN_SCRIPT = 'src="http://localhost:8100/wp-content/plugins/simpleanalytics/resources/js/inactive.js">'; +const SA_INACTIVE_ADMIN_SCRIPT = 'src="http://127.0.0.1:8100/wp-content/plugins/simpleanalytics/resources/js/inactive.js">'; const WP_PLUGIN_ROW_SELECTOR = 'tr[data-slug="simpleanalytics"]'; const WP_ACTIVATE_PLUGIN_SELECTOR = '#activate-simpleanalytics'; From e1ac806249a28714969d9d0c335d10b99b0ab5ad Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 12:23:32 +0000 Subject: [PATCH 056/158] wip --- tests/Browser/PluginSettingsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 3962d59..aaa116f 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -6,7 +6,7 @@ const SA_ADMIN_NOTICE = ''; const SA_DEFAULT_SCRIPT = 'src="https://scripts.simpleanalyticscdn.com/latest.js">'; -const SA_INACTIVE_ADMIN_SCRIPT = 'src="http://127.0.0.1:8100/wp-content/plugins/simpleanalytics/resources/js/inactive.js">'; +const SA_INACTIVE_ADMIN_SCRIPT = 'src="http://127.0.0.1:8100/wp-content/plugins/simpleanalytics/resources/js/inactive.js"'; const WP_PLUGIN_ROW_SELECTOR = 'tr[data-slug="simpleanalytics"]'; const WP_ACTIVATE_PLUGIN_SELECTOR = '#activate-simpleanalytics'; From efdada91254867c749b4526a2af2d8bd0202d7f4 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 13:48:11 +0000 Subject: [PATCH 057/158] fix --- src/Plugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Plugin.php b/src/Plugin.php index 8a1a08a..3e3c978 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -46,7 +46,7 @@ public function boot(): void public function onInit(): void { - $tracking = $this->trackingRules->hasExcludedIp() && $this->trackingRules->hasExcludedUserRole(); + $tracking = ! $this->trackingRules->hasExcludedIp() && ! $this->trackingRules->hasExcludedUserRole(); if ($tracking && $this->settings->get(SettingName::NOSCRIPT)) { AddNoScriptTag::register(); From 0738fbacee897ce16df928eb4e4f2587e11e5f10 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 13:56:35 +0000 Subject: [PATCH 058/158] wip --- src/Plugin.php | 13 +++++-------- src/TrackingRules.php | 9 ++++++++- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/Plugin.php b/src/Plugin.php index 3e3c978..c195c44 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -48,18 +48,15 @@ public function onInit(): void { $tracking = ! $this->trackingRules->hasExcludedIp() && ! $this->trackingRules->hasExcludedUserRole(); - if ($tracking && $this->settings->get(SettingName::NOSCRIPT)) { - AddNoScriptTag::register(); - } - - if (! $tracking) { - AddInactiveComment::register(); - } - if ($tracking) { $this->scripts->push(new AnalyticsScript); } else { $this->scripts->push(new InactiveScript); + AddInactiveComment::register(); + } + + if ($tracking && $this->settings->get(SettingName::NOSCRIPT)) { + AddNoScriptTag::register(); } if ($this->settings->boolean(SettingName::AUTOMATED_EVENTS)) { diff --git a/src/TrackingRules.php b/src/TrackingRules.php index f71c629..02d0505 100644 --- a/src/TrackingRules.php +++ b/src/TrackingRules.php @@ -24,9 +24,16 @@ public function hasExcludedIp(): bool public function hasExcludedUserRole(): bool { - if (! is_user_logged_in()) return false; + if (! is_user_logged_in()) { + return false; + } $needle = $this->settings->array(SettingName::EXCLUDED_ROLES); + + if ($needle === []) { + return true; + } + $current = wp_get_current_user()->roles; return array_intersect($needle, $current) !== []; From 9be45265665e2508fcbdb2665a650e7e3e48c301 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 14:00:51 +0000 Subject: [PATCH 059/158] wip --- tests/Browser/PluginSettingsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index aaa116f..10da0be 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -6,7 +6,7 @@ const SA_ADMIN_NOTICE = ''; const SA_DEFAULT_SCRIPT = 'src="https://scripts.simpleanalyticscdn.com/latest.js">'; -const SA_INACTIVE_ADMIN_SCRIPT = 'src="http://127.0.0.1:8100/wp-content/plugins/simpleanalytics/resources/js/inactive.js"'; +const SA_INACTIVE_ADMIN_SCRIPT = 'src="http://localhost:8100/wp-content/plugins/simpleanalytics/resources/js/inactive.js"'; const WP_PLUGIN_ROW_SELECTOR = 'tr[data-slug="simpleanalytics"]'; const WP_ACTIVATE_PLUGIN_SELECTOR = '#activate-simpleanalytics'; From 9fef90267efe57c2b928e6a14bcb7b7a9e760b0a Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 14:23:09 +0000 Subject: [PATCH 060/158] custom domain --- tests/Browser/PluginSettingsTest.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 10da0be..8fcb953 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -35,3 +35,14 @@ ->toContain(SA_ADMIN_NOTICE) ->toContain(SA_INACTIVE_ADMIN_SCRIPT); }); + +it('adds a script with a custom domain name', function () { + asAdmin() + ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=general'¬) + ->fill('simpleanalytics_custom_domain', 'mydomain.com') + ->click('Save Changes') + ->assertValue('simpleanalytics_custom_domain', 'mydomain.com'); + + expect(visit('http://localhost:8100')->content()) + ->toContain(str_replace('scripts.simpleanalyticscdn.com', 'mydomain.com', SA_DEFAULT_SCRIPT)); +}); From 9e352d532e4578e0c59d7f1513925a77e82c336d Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 14:23:40 +0000 Subject: [PATCH 061/158] typo --- tests/Browser/PluginSettingsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 8fcb953..3eceaf4 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -38,7 +38,7 @@ it('adds a script with a custom domain name', function () { asAdmin() - ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=general'¬) + ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=general') ->fill('simpleanalytics_custom_domain', 'mydomain.com') ->click('Save Changes') ->assertValue('simpleanalytics_custom_domain', 'mydomain.com'); From 48aa63147adb05c5e40e67d8e97e9430cc2cad13 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 14:27:11 +0000 Subject: [PATCH 062/158] wip --- tests/Browser/PluginSettingsTest.php | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 3eceaf4..e4815b8 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -8,19 +8,14 @@ const SA_DEFAULT_SCRIPT = 'src="https://scripts.simpleanalyticscdn.com/latest.js">'; const SA_INACTIVE_ADMIN_SCRIPT = 'src="http://localhost:8100/wp-content/plugins/simpleanalytics/resources/js/inactive.js"'; -const WP_PLUGIN_ROW_SELECTOR = 'tr[data-slug="simpleanalytics"]'; -const WP_ACTIVATE_PLUGIN_SELECTOR = '#activate-simpleanalytics'; -const WP_DEACTIVATE_PLUGIN_SELECTOR = '#deactivate-simpleanalytics'; -const WP_PLUGIN_MENU_ITEM = 'a[href="options-general.php?page=simpleanalytics"]'; - it('can be activated', function () { asAdmin() ->navigate('http://localhost:8100/wp-admin/plugins.php') ->screenshot() - ->assertPresent(WP_PLUGIN_ROW_SELECTOR) - ->click(WP_ACTIVATE_PLUGIN_SELECTOR) - ->assertPresent(WP_PLUGIN_MENU_ITEM) - ->assertPresent(WP_DEACTIVATE_PLUGIN_SELECTOR); + ->assertPresent('tr[data-slug="simpleanalytics"]') + ->click('#activate-simpleanalytics') + ->assertPresent('a[href="options-general.php?page=simpleanalytics"]') + ->assertPresent('#deactivate-simpleanalytics'); }); it('adds a script by default', function () { From 29ef71177633bc303eecc88cefd38c8dd35e3049 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 14:29:28 +0000 Subject: [PATCH 063/158] wip --- tests/Browser/PluginSettingsTest.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index e4815b8..948efde 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -38,6 +38,17 @@ ->click('Save Changes') ->assertValue('simpleanalytics_custom_domain', 'mydomain.com'); - expect(visit('http://localhost:8100')->content()) - ->toContain(str_replace('scripts.simpleanalyticscdn.com', 'mydomain.com', SA_DEFAULT_SCRIPT)); + $script = str_replace('scripts.simpleanalyticscdn.com', 'mydomain.com', SA_DEFAULT_SCRIPT); + + expect(visit('http://localhost:8100')->content())->toContain($script); +}); + +it('adds a script with ignored pages', function () { + asAdmin() + ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules') + ->fill('simpleanalytics_ignore_pages', '/vouchers') + ->click('Save Changes') + ->assertValue('simpleanalytics_ignore_pages', '/vouchers'); + + expect(visit('http://localhost:8100')->content())->toContain('data-ignore-pages="/vouchers"'); }); From 76166a861e8136f48c1e2494e664e22b4eead612 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 17:00:59 +0000 Subject: [PATCH 064/158] wip --- .github/workflows/tests.yml | 3 +++ tests/Browser/PluginSettingsTest.php | 26 ++++++++++++++++++++++---- tests/Pest.php | 23 ++++++++++++++++++++--- 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c594c1a..bd07956 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -87,6 +87,9 @@ jobs: --path=wordpress \ --skip-email \ --allow-root + wp user create author author@localhost --role=author --user_pass=author + wp user create editor editor@localhost --role=editor --user_pass=editor + wp user create subscriber subscriber@localhost --role=subscriber --user_pass=subscriber - name: Show current config values run: wp config list --path=wordpress --allow-root diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 948efde..9ddd6e5 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -2,7 +2,7 @@ namespace Tests\Browser; -use function Tests\asAdmin; +use function Tests\{asAdmin, asAuthor, asEditor}; const SA_ADMIN_NOTICE = ''; const SA_DEFAULT_SCRIPT = 'src="https://scripts.simpleanalyticscdn.com/latest.js">'; @@ -20,13 +20,13 @@ it('adds a script by default', function () { $homePage = visit('http://localhost:8100'); - expect($homePage->content())->dump()->toContain(SA_DEFAULT_SCRIPT); + expect($homePage->content())->toContain(SA_DEFAULT_SCRIPT); }); -it('adds a comment when an authenticated user visits', function () { +it('adds inactive script for authenticated users by default', function () { $homePage = asAdmin()->navigate('http://localhost:8100'); - expect($homePage->content())->dump() + expect($homePage->content()) ->toContain(SA_ADMIN_NOTICE) ->toContain(SA_INACTIVE_ADMIN_SCRIPT); }); @@ -52,3 +52,21 @@ expect(visit('http://localhost:8100')->content())->toContain('data-ignore-pages="/vouchers"'); }); + +it('adds inactive script for selected user roles', function () { + asAdmin() + ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules') + ->check('simpleanalytics_exclude_user_roles-editor') + ->check('simpleanalytics_exclude_user_roles-author') + ->click('Save Changes') + ->assertChecked('simpleanalytics_exclude_user_roles-editor') + ->assertChecked('simpleanalytics_exclude_user_roles-author'); + + expect(asEditor()->navigate('http://localhost:8100')->content()) + ->toContain(SA_ADMIN_NOTICE) + ->toContain(SA_INACTIVE_ADMIN_SCRIPT); + + expect(asAuthor()->navigate('http://localhost:8100')->content()) + ->toContain(SA_ADMIN_NOTICE) + ->toContain(SA_INACTIVE_ADMIN_SCRIPT); +}); diff --git a/tests/Pest.php b/tests/Pest.php index cf4419d..2f5e7c0 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -13,6 +13,8 @@ | */ +use Pest\Browser\Api\Webpage; + pest()->extend(TestCase::class)->in('Feature'); /* @@ -41,11 +43,26 @@ | */ -function asAdmin() +function asUser(string $login, string $password): Webpage { return visit('http://localhost:8100/wp-admin') - ->fill('user_login', 'admin') - ->fill('user_pass', 'admin') + ->fill('user_login', $login) + ->fill('user_pass', $password) ->press('wp-submit') ->assertUrlIs('http://localhost:8100/wp-admin'); } + +function asAdmin() +{ + return asUser('admin', 'admin'); +} + +function asAuthor() +{ + return asUser('author', 'author'); +} + +function asEditor() +{ + return asUser('editor', 'editor'); +} From 248d70ee215b75e67079fbc3ed8272b54254007c Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 17:03:42 +0000 Subject: [PATCH 065/158] wip --- .github/workflows/tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index bd07956..1d724b4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -87,9 +87,9 @@ jobs: --path=wordpress \ --skip-email \ --allow-root - wp user create author author@localhost --role=author --user_pass=author - wp user create editor editor@localhost --role=editor --user_pass=editor - wp user create subscriber subscriber@localhost --role=subscriber --user_pass=subscriber + wp user create author author@localhost --role=author --user_pass=author --path=wordpress + wp user create editor editor@localhost --role=editor --user_pass=editor --path=wordpress + wp user create subscriber subscriber@localhost --role=subscriber --user_pass=subscriber --path=wordpress - name: Show current config values run: wp config list --path=wordpress --allow-root From f1efa1d6402a077e9c93b53a96d2c20ec6cd69b3 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 17:07:55 +0000 Subject: [PATCH 066/158] wip --- .github/workflows/tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1d724b4..1156887 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -87,9 +87,9 @@ jobs: --path=wordpress \ --skip-email \ --allow-root - wp user create author author@localhost --role=author --user_pass=author --path=wordpress - wp user create editor editor@localhost --role=editor --user_pass=editor --path=wordpress - wp user create subscriber subscriber@localhost --role=subscriber --user_pass=subscriber --path=wordpress + wp user create author author@local.test --role=author --user_pass=author --path=wordpress + wp user create editor editor@local.test --role=editor --user_pass=editor --path=wordpress + wp user create subscriber subscriber@local.test --role=subscriber --user_pass=subscriber --path=wordpress - name: Show current config values run: wp config list --path=wordpress --allow-root From 2f224d18b1014827ff8388b608b1dcde396b0ae2 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 17:09:58 +0000 Subject: [PATCH 067/158] wip --- tests/Pest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Pest.php b/tests/Pest.php index 2f5e7c0..3105897 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -43,7 +43,7 @@ | */ -function asUser(string $login, string $password): Webpage +function asUser(string $login, string $password) { return visit('http://localhost:8100/wp-admin') ->fill('user_login', $login) From 9588940893b62e6391af8780e9819d2896d85644 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 17:16:43 +0000 Subject: [PATCH 068/158] wip --- tests/Browser/PluginSettingsTest.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 9ddd6e5..286bb83 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -4,8 +4,8 @@ use function Tests\{asAdmin, asAuthor, asEditor}; -const SA_ADMIN_NOTICE = ''; const SA_DEFAULT_SCRIPT = 'src="https://scripts.simpleanalyticscdn.com/latest.js">'; +const SA_INACTIVE_ADMIN_NOTICE = ''; const SA_INACTIVE_ADMIN_SCRIPT = 'src="http://localhost:8100/wp-content/plugins/simpleanalytics/resources/js/inactive.js"'; it('can be activated', function () { @@ -27,7 +27,7 @@ $homePage = asAdmin()->navigate('http://localhost:8100'); expect($homePage->content()) - ->toContain(SA_ADMIN_NOTICE) + ->toContain(SA_INACTIVE_ADMIN_NOTICE) ->toContain(SA_INACTIVE_ADMIN_SCRIPT); }); @@ -54,19 +54,23 @@ }); it('adds inactive script for selected user roles', function () { - asAdmin() - ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules') + $admin = asAdmin(); + + $admin->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules') ->check('simpleanalytics_exclude_user_roles-editor') ->check('simpleanalytics_exclude_user_roles-author') ->click('Save Changes') ->assertChecked('simpleanalytics_exclude_user_roles-editor') ->assertChecked('simpleanalytics_exclude_user_roles-author'); + expect($admin->navigate('http://localhost:8100')->content()) + ->toContain(SA_DEFAULT_SCRIPT); + expect(asEditor()->navigate('http://localhost:8100')->content()) - ->toContain(SA_ADMIN_NOTICE) + ->toContain(SA_INACTIVE_ADMIN_NOTICE) ->toContain(SA_INACTIVE_ADMIN_SCRIPT); expect(asAuthor()->navigate('http://localhost:8100')->content()) - ->toContain(SA_ADMIN_NOTICE) + ->toContain(SA_INACTIVE_ADMIN_NOTICE) ->toContain(SA_INACTIVE_ADMIN_SCRIPT); }); From 6b5c935ebe6f5c1824cfdf658161ceb1fc4b7e21 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 17:19:05 +0000 Subject: [PATCH 069/158] wip --- tests/Browser/PluginSettingsTest.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 286bb83..01d633e 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -31,18 +31,6 @@ ->toContain(SA_INACTIVE_ADMIN_SCRIPT); }); -it('adds a script with a custom domain name', function () { - asAdmin() - ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=general') - ->fill('simpleanalytics_custom_domain', 'mydomain.com') - ->click('Save Changes') - ->assertValue('simpleanalytics_custom_domain', 'mydomain.com'); - - $script = str_replace('scripts.simpleanalyticscdn.com', 'mydomain.com', SA_DEFAULT_SCRIPT); - - expect(visit('http://localhost:8100')->content())->toContain($script); -}); - it('adds a script with ignored pages', function () { asAdmin() ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules') @@ -74,3 +62,15 @@ ->toContain(SA_INACTIVE_ADMIN_NOTICE) ->toContain(SA_INACTIVE_ADMIN_SCRIPT); }); + +it('adds a script with a custom domain name', function () { + asAdmin() + ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=general') + ->fill('simpleanalytics_custom_domain', 'mydomain.com') + ->click('Save Changes') + ->assertValue('simpleanalytics_custom_domain', 'mydomain.com'); + + $script = str_replace('scripts.simpleanalyticscdn.com', 'mydomain.com', SA_DEFAULT_SCRIPT); + + expect(visit('http://localhost:8100')->content())->toContain($script); +}); From 873043a1b83cb29670acf9809e878206b6ef0c09 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 17:32:46 +0000 Subject: [PATCH 070/158] wip --- tests/Browser/PluginSettingsTest.php | 44 ++++++++++++---------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 01d633e..63a3f8b 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -4,9 +4,9 @@ use function Tests\{asAdmin, asAuthor, asEditor}; -const SA_DEFAULT_SCRIPT = 'src="https://scripts.simpleanalyticscdn.com/latest.js">'; -const SA_INACTIVE_ADMIN_NOTICE = ''; -const SA_INACTIVE_ADMIN_SCRIPT = 'src="http://localhost:8100/wp-content/plugins/simpleanalytics/resources/js/inactive.js"'; +const SA_DEFAULT_SCRIPT_SELECTOR = 'script[src="https://scripts.simpleanalyticscdn.com/latest.js"]'; +const SA_INACTIVE_ADMIN_SCRIPT_SELECTOR = 'script[src="http://localhost:8100/wp-content/plugins/simpleanalytics/resources/js/inactive.js"]'; +const SA_INACTIVE_ADMIN_COMMENT = ''; it('can be activated', function () { asAdmin() @@ -19,16 +19,14 @@ }); it('adds a script by default', function () { - $homePage = visit('http://localhost:8100'); - expect($homePage->content())->toContain(SA_DEFAULT_SCRIPT); + visit('http://localhost:8100')->assertPresent(SA_DEFAULT_SCRIPT_SELECTOR); }); it('adds inactive script for authenticated users by default', function () { - $homePage = asAdmin()->navigate('http://localhost:8100'); - - expect($homePage->content()) - ->toContain(SA_INACTIVE_ADMIN_NOTICE) - ->toContain(SA_INACTIVE_ADMIN_SCRIPT); + asAdmin() + ->navigate('http://localhost:8100') + ->assertPresent('script[url="http://localhost:8100/wp-content/plugins/simpleanalytics/resources/js/inactive.js"]') + ->assertSourceHas(SA_INACTIVE_ADMIN_COMMENT); }); it('adds a script with ignored pages', function () { @@ -38,29 +36,27 @@ ->click('Save Changes') ->assertValue('simpleanalytics_ignore_pages', '/vouchers'); - expect(visit('http://localhost:8100')->content())->toContain('data-ignore-pages="/vouchers"'); + visit('http://localhost:8100')->assertSourceHas('data-ignore-pages="/vouchers"'); }); it('adds inactive script for selected user roles', function () { - $admin = asAdmin(); - - $admin->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules') + $admin = asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules') ->check('simpleanalytics_exclude_user_roles-editor') ->check('simpleanalytics_exclude_user_roles-author') ->click('Save Changes') ->assertChecked('simpleanalytics_exclude_user_roles-editor') ->assertChecked('simpleanalytics_exclude_user_roles-author'); - expect($admin->navigate('http://localhost:8100')->content()) - ->toContain(SA_DEFAULT_SCRIPT); + $admin->navigate('http://localhost:8100') + ->assertPresent(SA_DEFAULT_SCRIPT_SELECTOR); - expect(asEditor()->navigate('http://localhost:8100')->content()) - ->toContain(SA_INACTIVE_ADMIN_NOTICE) - ->toContain(SA_INACTIVE_ADMIN_SCRIPT); + asAuthor()->navigate('http://localhost:8100') + ->assertPresent(SA_INACTIVE_ADMIN_SCRIPT_SELECTOR) + ->assertSourceHas(SA_INACTIVE_ADMIN_COMMENT); - expect(asAuthor()->navigate('http://localhost:8100')->content()) - ->toContain(SA_INACTIVE_ADMIN_NOTICE) - ->toContain(SA_INACTIVE_ADMIN_SCRIPT); + asEditor()->navigate('http://localhost:8100') + ->assertPresent(SA_INACTIVE_ADMIN_SCRIPT_SELECTOR) + ->assertSourceHas(SA_INACTIVE_ADMIN_COMMENT); }); it('adds a script with a custom domain name', function () { @@ -70,7 +66,5 @@ ->click('Save Changes') ->assertValue('simpleanalytics_custom_domain', 'mydomain.com'); - $script = str_replace('scripts.simpleanalyticscdn.com', 'mydomain.com', SA_DEFAULT_SCRIPT); - - expect(visit('http://localhost:8100')->content())->toContain($script); + visit('http://localhost:8100')->assertPresent('script[src="https://mydomain.com/latest.js"]'); }); From ec1e1648b0d3f1694710a5a5cd5b0a5dd1f84ebb Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 17:41:51 +0000 Subject: [PATCH 071/158] wip --- tests/Browser/PluginSettingsTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 63a3f8b..85711e0 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -25,6 +25,7 @@ it('adds inactive script for authenticated users by default', function () { asAdmin() ->navigate('http://localhost:8100') + ->dd() ->assertPresent('script[url="http://localhost:8100/wp-content/plugins/simpleanalytics/resources/js/inactive.js"]') ->assertSourceHas(SA_INACTIVE_ADMIN_COMMENT); }); From cc6a48e134d0321c0660d14b4e4bbf705fe2e166 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 17:43:59 +0000 Subject: [PATCH 072/158] wip --- tests/Browser/PluginSettingsTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 85711e0..4dba2bb 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -25,8 +25,7 @@ it('adds inactive script for authenticated users by default', function () { asAdmin() ->navigate('http://localhost:8100') - ->dd() - ->assertPresent('script[url="http://localhost:8100/wp-content/plugins/simpleanalytics/resources/js/inactive.js"]') + ->assertPresent('script[src="http://localhost:8100/wp-content/plugins/simpleanalytics/resources/js/inactive.js"]') ->assertSourceHas(SA_INACTIVE_ADMIN_COMMENT); }); From 09210ee4134b24823479f521100cf89e7ca66913 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 18:09:25 +0000 Subject: [PATCH 073/158] wip --- tests/Browser/PluginSettingsTest.php | 141 +++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 4dba2bb..c782f31 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -7,6 +7,7 @@ const SA_DEFAULT_SCRIPT_SELECTOR = 'script[src="https://scripts.simpleanalyticscdn.com/latest.js"]'; const SA_INACTIVE_ADMIN_SCRIPT_SELECTOR = 'script[src="http://localhost:8100/wp-content/plugins/simpleanalytics/resources/js/inactive.js"]'; const SA_INACTIVE_ADMIN_COMMENT = ''; +const SA_NOSCRIPT_SELECTOR = 'noscript img[src="https://queue.simpleanalyticscdn.com/noscript.gif"][alt=""][referrerpolicy="no-referrer-when-downgrade"]'; it('can be activated', function () { asAdmin() @@ -68,3 +69,143 @@ visit('http://localhost:8100')->assertPresent('script[src="https://mydomain.com/latest.js"]'); }); + +it('adds a script with collect do not track enabled', function () { + asAdmin() + ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') + ->check('simpleanalytics_collect_dnt') + ->click('Save Changes') + ->assertChecked('simpleanalytics_collect_dnt'); + + visit('http://localhost:8100')->assertSourceHas('data-collect-dnt="true"'); +}); + +it('adds a script with hash mode enabled', function () { + asAdmin() + ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') + ->check('simpleanalytics_hash_mode') + ->click('Save Changes') + ->assertChecked('simpleanalytics_hash_mode'); + + visit('http://localhost:8100')->assertSourceHas('data-mode="hash"'); +}); + +it('adds a script with manually collect page views enabled', function () { + asAdmin() + ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') + ->check('simpleanalytics_manual_collect') + ->click('Save Changes') + ->assertChecked('simpleanalytics_manual_collect'); + + visit('http://localhost:8100')->assertSourceHas('data-auto-collect="true"'); +}); + +it('adds noscript tag when support no javascript mode is enabled', function () { + asAdmin() + ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') + ->check('simpleanalytics_noscript') + ->click('Save Changes') + ->assertChecked('simpleanalytics_noscript'); + + visit('http://localhost:8100')->assertPresent(SA_NOSCRIPT_SELECTOR); +}); + +it('adds a script with onload callback', function () { + asAdmin() + ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') + ->fill('simpleanalytics_onload_callback', 'sa_event("My event")') + ->click('Save Changes') + ->assertValue('simpleanalytics_onload_callback', 'sa_event("My event")'); + + visit('http://localhost:8100')->assertSourceHas('data-onload="sa_event(\"My event\")"'); +}); + +it('adds a script with overwrite domain name', function () { + asAdmin() + ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') + ->fill('simpleanalytics_hostname', 'example.com') + ->click('Save Changes') + ->assertValue('simpleanalytics_hostname', 'example.com'); + + visit('http://localhost:8100')->assertSourceHas('data-hostname="example.com"'); +}); + +it('adds a script with global variable name', function () { + asAdmin() + ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') + ->fill('simpleanalytics_sa_global', 'ba_event') + ->click('Save Changes') + ->assertValue('simpleanalytics_sa_global', 'ba_event'); + + visit('http://localhost:8100')->assertSourceHas('data-sa-global="ba_event"'); +}); + +it('adds automated events script when collect automated events is enabled', function () { + asAdmin() + ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') + ->check('simpleanalytics_automated_events') + ->click('Save Changes') + ->assertChecked('simpleanalytics_automated_events'); + + visit('http://localhost:8100')->assertPresent('script[src="https://scripts.simpleanalyticscdn.com/auto-events.js"]'); +}); + +it('adds automated events script with auto collect downloads', function () { + asAdmin() + ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') + ->check('simpleanalytics_automated_events') + ->fill('simpleanalytics_event_collect_downloads', 'outbound,emails,downloads') + ->click('Save Changes') + ->assertChecked('simpleanalytics_automated_events') + ->assertValue('simpleanalytics_event_collect_downloads', 'outbound,emails,downloads'); + + visit('http://localhost:8100')->assertSourceHas('data-collect="outbound,emails,downloads"'); +}); + +it('adds automated events script with download file extensions', function () { + asAdmin() + ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') + ->check('simpleanalytics_automated_events') + ->fill('simpleanalytics_event_extensions', 'pdf,zip') + ->click('Save Changes') + ->assertChecked('simpleanalytics_automated_events') + ->assertValue('simpleanalytics_event_extensions', 'pdf,zip'); + + visit('http://localhost:8100')->assertSourceHas('data-extensions="pdf,zip"'); +}); + +it('adds automated events script with use titles of page enabled', function () { + asAdmin() + ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') + ->check('simpleanalytics_automated_events') + ->check('simpleanalytics_event_use_title') + ->click('Save Changes') + ->assertChecked('simpleanalytics_automated_events') + ->assertChecked('simpleanalytics_event_use_title'); + + visit('http://localhost:8100')->assertSourceHas('data-use-title'); +}); + +it('adds automated events script with use full urls enabled', function () { + asAdmin() + ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') + ->check('simpleanalytics_automated_events') + ->check('simpleanalytics_event_full_urls') + ->click('Save Changes') + ->assertChecked('simpleanalytics_automated_events') + ->assertChecked('simpleanalytics_event_full_urls'); + + visit('http://localhost:8100')->assertSourceHas('data-full-urls'); +}); + +it('adds automated events script with override global', function () { + asAdmin() + ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') + ->check('simpleanalytics_automated_events') + ->fill('simpleanalytics_event_sa_global', 'ba_event') + ->click('Save Changes') + ->assertChecked('simpleanalytics_automated_events') + ->assertValue('simpleanalytics_event_sa_global', 'ba_event'); + + visit('http://localhost:8100')->assertSourceHas('data-sa-global="ba_event"'); +}); From 759c27b207d2038b7bb6a795add3beb04d020aa1 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 18:23:58 +0000 Subject: [PATCH 074/158] wip --- tests/Browser/PluginSettingsTest.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index c782f31..c764991 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -120,16 +120,6 @@ visit('http://localhost:8100')->assertSourceHas('data-onload="sa_event(\"My event\")"'); }); -it('adds a script with overwrite domain name', function () { - asAdmin() - ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') - ->fill('simpleanalytics_hostname', 'example.com') - ->click('Save Changes') - ->assertValue('simpleanalytics_hostname', 'example.com'); - - visit('http://localhost:8100')->assertSourceHas('data-hostname="example.com"'); -}); - it('adds a script with global variable name', function () { asAdmin() ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') @@ -209,3 +199,13 @@ visit('http://localhost:8100')->assertSourceHas('data-sa-global="ba_event"'); }); + +it('adds a script with overwrite domain name', function () { + asAdmin() + ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') + ->fill('simpleanalytics_hostname', 'example.com') + ->click('Save Changes') + ->assertValue('simpleanalytics_hostname', 'example.com'); + + visit('http://localhost:8100')->assertSourceHas('data-hostname="example.com"'); +}); From 77c2c40f21f02e1bd85c1e37b5f9b6a8ce5c8083 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 18:25:50 +0000 Subject: [PATCH 075/158] wip --- tests/Browser/PluginSettingsTest.php | 63 +++++++++++----------------- 1 file changed, 25 insertions(+), 38 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index c764991..5de9386 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -4,10 +4,10 @@ use function Tests\{asAdmin, asAuthor, asEditor}; -const SA_DEFAULT_SCRIPT_SELECTOR = 'script[src="https://scripts.simpleanalyticscdn.com/latest.js"]'; -const SA_INACTIVE_ADMIN_SCRIPT_SELECTOR = 'script[src="http://localhost:8100/wp-content/plugins/simpleanalytics/resources/js/inactive.js"]'; -const SA_INACTIVE_ADMIN_COMMENT = ''; -const SA_NOSCRIPT_SELECTOR = 'noscript img[src="https://queue.simpleanalyticscdn.com/noscript.gif"][alt=""][referrerpolicy="no-referrer-when-downgrade"]'; +const DEFAULT_SCRIPT_SELECTOR = 'script[src="https://scripts.simpleanalyticscdn.com/latest.js"]'; +const INACTIVE_ADMIN_SCRIPT_SELECTOR = 'script[src="http://localhost:8100/wp-content/plugins/simpleanalytics/resources/js/inactive.js"]'; +const INACTIVE_ADMIN_COMMENT = ''; +const NOSCRIPT_SELECTOR = 'noscript img[src="https://queue.simpleanalyticscdn.com/noscript.gif"][alt=""][referrerpolicy="no-referrer-when-downgrade"]'; it('can be activated', function () { asAdmin() @@ -20,14 +20,14 @@ }); it('adds a script by default', function () { - visit('http://localhost:8100')->assertPresent(SA_DEFAULT_SCRIPT_SELECTOR); + visit('http://localhost:8100')->assertPresent(DEFAULT_SCRIPT_SELECTOR); }); it('adds inactive script for authenticated users by default', function () { asAdmin() ->navigate('http://localhost:8100') ->assertPresent('script[src="http://localhost:8100/wp-content/plugins/simpleanalytics/resources/js/inactive.js"]') - ->assertSourceHas(SA_INACTIVE_ADMIN_COMMENT); + ->assertSourceHas(INACTIVE_ADMIN_COMMENT); }); it('adds a script with ignored pages', function () { @@ -49,15 +49,15 @@ ->assertChecked('simpleanalytics_exclude_user_roles-author'); $admin->navigate('http://localhost:8100') - ->assertPresent(SA_DEFAULT_SCRIPT_SELECTOR); + ->assertPresent(DEFAULT_SCRIPT_SELECTOR); asAuthor()->navigate('http://localhost:8100') - ->assertPresent(SA_INACTIVE_ADMIN_SCRIPT_SELECTOR) - ->assertSourceHas(SA_INACTIVE_ADMIN_COMMENT); + ->assertPresent(INACTIVE_ADMIN_SCRIPT_SELECTOR) + ->assertSourceHas(INACTIVE_ADMIN_COMMENT); asEditor()->navigate('http://localhost:8100') - ->assertPresent(SA_INACTIVE_ADMIN_SCRIPT_SELECTOR) - ->assertSourceHas(SA_INACTIVE_ADMIN_COMMENT); + ->assertPresent(INACTIVE_ADMIN_SCRIPT_SELECTOR) + ->assertSourceHas(INACTIVE_ADMIN_COMMENT); }); it('adds a script with a custom domain name', function () { @@ -71,8 +71,7 @@ }); it('adds a script with collect do not track enabled', function () { - asAdmin() - ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') + asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') ->check('simpleanalytics_collect_dnt') ->click('Save Changes') ->assertChecked('simpleanalytics_collect_dnt'); @@ -81,8 +80,7 @@ }); it('adds a script with hash mode enabled', function () { - asAdmin() - ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') + asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') ->check('simpleanalytics_hash_mode') ->click('Save Changes') ->assertChecked('simpleanalytics_hash_mode'); @@ -91,8 +89,7 @@ }); it('adds a script with manually collect page views enabled', function () { - asAdmin() - ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') + asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') ->check('simpleanalytics_manual_collect') ->click('Save Changes') ->assertChecked('simpleanalytics_manual_collect'); @@ -101,18 +98,16 @@ }); it('adds noscript tag when support no javascript mode is enabled', function () { - asAdmin() - ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') + asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') ->check('simpleanalytics_noscript') ->click('Save Changes') ->assertChecked('simpleanalytics_noscript'); - visit('http://localhost:8100')->assertPresent(SA_NOSCRIPT_SELECTOR); + visit('http://localhost:8100')->assertPresent(NOSCRIPT_SELECTOR); }); it('adds a script with onload callback', function () { - asAdmin() - ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') + asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') ->fill('simpleanalytics_onload_callback', 'sa_event("My event")') ->click('Save Changes') ->assertValue('simpleanalytics_onload_callback', 'sa_event("My event")'); @@ -121,8 +116,7 @@ }); it('adds a script with global variable name', function () { - asAdmin() - ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') + asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') ->fill('simpleanalytics_sa_global', 'ba_event') ->click('Save Changes') ->assertValue('simpleanalytics_sa_global', 'ba_event'); @@ -131,8 +125,7 @@ }); it('adds automated events script when collect automated events is enabled', function () { - asAdmin() - ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') + asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') ->check('simpleanalytics_automated_events') ->click('Save Changes') ->assertChecked('simpleanalytics_automated_events'); @@ -141,8 +134,7 @@ }); it('adds automated events script with auto collect downloads', function () { - asAdmin() - ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') + asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') ->check('simpleanalytics_automated_events') ->fill('simpleanalytics_event_collect_downloads', 'outbound,emails,downloads') ->click('Save Changes') @@ -153,8 +145,7 @@ }); it('adds automated events script with download file extensions', function () { - asAdmin() - ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') + asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') ->check('simpleanalytics_automated_events') ->fill('simpleanalytics_event_extensions', 'pdf,zip') ->click('Save Changes') @@ -165,8 +156,7 @@ }); it('adds automated events script with use titles of page enabled', function () { - asAdmin() - ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') + asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') ->check('simpleanalytics_automated_events') ->check('simpleanalytics_event_use_title') ->click('Save Changes') @@ -177,8 +167,7 @@ }); it('adds automated events script with use full urls enabled', function () { - asAdmin() - ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') + asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') ->check('simpleanalytics_automated_events') ->check('simpleanalytics_event_full_urls') ->click('Save Changes') @@ -189,8 +178,7 @@ }); it('adds automated events script with override global', function () { - asAdmin() - ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') + asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') ->check('simpleanalytics_automated_events') ->fill('simpleanalytics_event_sa_global', 'ba_event') ->click('Save Changes') @@ -201,8 +189,7 @@ }); it('adds a script with overwrite domain name', function () { - asAdmin() - ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') + asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') ->fill('simpleanalytics_hostname', 'example.com') ->click('Save Changes') ->assertValue('simpleanalytics_hostname', 'example.com'); From 0b2a8d614490bdec4f4fb0269b3f1c0a666a1596 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 18:28:08 +0000 Subject: [PATCH 076/158] wip --- tests/Browser/PluginSettingsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 5de9386..d65b52a 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -112,7 +112,7 @@ ->click('Save Changes') ->assertValue('simpleanalytics_onload_callback', 'sa_event("My event")'); - visit('http://localhost:8100')->assertSourceHas('data-onload="sa_event(\"My event\")"'); + visit('http://localhost:8100')->dd()->assertSourceHas('data-onload="sa_event(\"My event\")"'); }); it('adds a script with global variable name', function () { From cebd00a42712ad68d004b429bd9e8bdd434c23d8 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 18:32:58 +0000 Subject: [PATCH 077/158] wip --- tests/Browser/PluginSettingsTest.php | 32 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index d65b52a..49e297f 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -60,16 +60,6 @@ ->assertSourceHas(INACTIVE_ADMIN_COMMENT); }); -it('adds a script with a custom domain name', function () { - asAdmin() - ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=general') - ->fill('simpleanalytics_custom_domain', 'mydomain.com') - ->click('Save Changes') - ->assertValue('simpleanalytics_custom_domain', 'mydomain.com'); - - visit('http://localhost:8100')->assertPresent('script[src="https://mydomain.com/latest.js"]'); -}); - it('adds a script with collect do not track enabled', function () { asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') ->check('simpleanalytics_collect_dnt') @@ -112,7 +102,16 @@ ->click('Save Changes') ->assertValue('simpleanalytics_onload_callback', 'sa_event("My event")'); - visit('http://localhost:8100')->dd()->assertSourceHas('data-onload="sa_event(\"My event\")"'); + visit('http://localhost:8100')->assertSourceHas('data-onload="sa_event(\"My event\")"'); +}); + +it('adds a script with overwrite domain name', function () { + asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') + ->fill('simpleanalytics_hostname', 'example.com') + ->click('Save Changes') + ->assertValue('simpleanalytics_hostname', 'example.com'); + + visit('http://localhost:8100')->assertSourceHas('data-hostname="example.com"'); }); it('adds a script with global variable name', function () { @@ -188,11 +187,12 @@ visit('http://localhost:8100')->assertSourceHas('data-sa-global="ba_event"'); }); -it('adds a script with overwrite domain name', function () { - asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') - ->fill('simpleanalytics_hostname', 'example.com') +it('adds a script with a custom domain name', function () { + asAdmin() + ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=general') + ->fill('simpleanalytics_custom_domain', 'mydomain.com') ->click('Save Changes') - ->assertValue('simpleanalytics_hostname', 'example.com'); + ->assertValue('simpleanalytics_custom_domain', 'mydomain.com'); - visit('http://localhost:8100')->assertSourceHas('data-hostname="example.com"'); + visit('http://localhost:8100')->assertPresent('script[src="https://mydomain.com/latest.js"]'); }); From e19411a1e48ba4ab893509809ff69ea214e549dd Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 18:43:38 +0000 Subject: [PATCH 078/158] wip --- tests/Browser/PluginSettingsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 49e297f..475a052 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -11,7 +11,7 @@ it('can be activated', function () { asAdmin() - ->navigate('http://localhost:8100/wp-admin/plugins.php') + ->click('Plugins') ->screenshot() ->assertPresent('tr[data-slug="simpleanalytics"]') ->click('#activate-simpleanalytics') From 7202873d9d43ea65732503263a5cf4e3e5500d7e Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 18:50:35 +0000 Subject: [PATCH 079/158] wip --- tests/Browser/PluginSettingsTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 475a052..a9f7b3a 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -19,6 +19,7 @@ ->assertPresent('#deactivate-simpleanalytics'); }); +/* it('adds a script by default', function () { visit('http://localhost:8100')->assertPresent(DEFAULT_SCRIPT_SELECTOR); }); @@ -196,3 +197,4 @@ visit('http://localhost:8100')->assertPresent('script[src="https://mydomain.com/latest.js"]'); }); +*/ From 42760e787a41275e537a05607d278bd379a0f1a4 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Fri, 31 Oct 2025 19:02:46 +0000 Subject: [PATCH 080/158] wip --- tests/Browser/PluginSettingsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index a9f7b3a..31a2fce 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -11,7 +11,7 @@ it('can be activated', function () { asAdmin() - ->click('Plugins') + ->navigate('http://localhost:8100/wp-admin/plugins.php') ->screenshot() ->assertPresent('tr[data-slug="simpleanalytics"]') ->click('#activate-simpleanalytics') From eac5669450b59da7c089ac19b8c5c8ad6342aea3 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 06:24:03 +0000 Subject: [PATCH 081/158] wip --- .github/workflows/tests.yml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1156887..3e3a050 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -99,9 +99,18 @@ jobs: PLUGIN_SLUG=$(basename "$GITHUB_WORKSPACE") ln -s "$GITHUB_WORKSPACE" "wordpress/wp-content/plugins/simpleanalytics" - - name: Start PHP server + - name: Start WordPress server run: | - php -S localhost:8100 -t wordpress > /dev/null 2>&1 & until curl -sSf http://localhost:8100 > /dev/null; do sleep 0.2; done + wp server --host=localhost --port=8100 --allow-root --path=wordpress > /tmp/wp-server.log 2>&1 & + # Health check + for i in {1..30}; do + if curl -sf http://localhost:8100/wp-login.php > /dev/null 2>&1; then + echo "WordPress server ready" + break + fi + [ $i -eq 30 ] && echo "Server failed to start" && cat /tmp/wp-server.log && exit 1 + sleep 1 + done - name: Install pnpm uses: pnpm/action-setup@v4 @@ -139,3 +148,9 @@ jobs: path: | tests/Browser/Screenshots retention-days: 30 + + - name: Debug server status + if: failure() + run: | + cat /tmp/wp-server.log || echo "No log file found" + ps aux | grep php || true From ec5ae4e124cb50f7b7b142d33596e8ae43a2f017 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 06:51:17 +0000 Subject: [PATCH 082/158] wip --- tests/Browser/PluginSettingsTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 31a2fce..49e297f 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -19,7 +19,6 @@ ->assertPresent('#deactivate-simpleanalytics'); }); -/* it('adds a script by default', function () { visit('http://localhost:8100')->assertPresent(DEFAULT_SCRIPT_SELECTOR); }); @@ -197,4 +196,3 @@ visit('http://localhost:8100')->assertPresent('script[src="https://mydomain.com/latest.js"]'); }); -*/ From 609c6db8348d5a3cf152a99cb9f8d2b3952f4415 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 11:43:02 +0000 Subject: [PATCH 083/158] wip --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3e3a050..2089c57 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -138,7 +138,7 @@ jobs: run: composer install --no-progress --prefer-dist --no-interaction - name: Run Pest tests - run: ./vendor/bin/pest + run: ./vendor/bin/pest --colors=always - name: Upload test results if: always() From 702e76c69fabb29da6e5984444c324d3264d1cc2 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 11:55:44 +0000 Subject: [PATCH 084/158] wip --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 10a94a1..35921fe 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "scripts": { "dev": "tailwindcss -i resources/css/settings.css -o build/css/settings.css --watch", "build": "tailwindcss build -i resources/css/settings.css -o build/css/settings.css", - "tests:install": "playwright install --with-deps chromium", + "tests:install": "playwright install --with-deps firefox", "tests": "playwright test" }, "devDependencies": { From 61747d5413d887dc8df561605e63d339b5725920 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 11:58:33 +0000 Subject: [PATCH 085/158] deps --- package.json | 2 +- pnpm-lock.yaml | 29 ++++++++++------------------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index 35921fe..0a84bbd 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,9 @@ "tests": "playwright test" }, "devDependencies": { - "@playwright/test": "^1.56.0", "@tailwindcss/forms": "^0.5.10", "@types/node": "^22.18.10", + "playwright": "^1.56.1", "tailwindcss": "^3.4.18" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e7f1bc4..8086be1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,15 +8,15 @@ importers: .: devDependencies: - '@playwright/test': - specifier: ^1.56.0 - version: 1.56.0 '@tailwindcss/forms': specifier: ^0.5.10 version: 0.5.10(tailwindcss@3.4.18(yaml@2.5.0)) '@types/node': specifier: ^22.18.10 version: 22.18.10 + playwright: + specifier: ^1.56.1 + version: 1.56.1 tailwindcss: specifier: ^3.4.18 version: 3.4.18(yaml@2.5.0) @@ -60,11 +60,6 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@playwright/test@1.56.0': - resolution: {integrity: sha512-Tzh95Twig7hUwwNe381/K3PggZBZblKUe2wv25oIpzWLr6Z0m4KgV1ZVIjnR6GM9ANEqjZD7XsZEa6JL/7YEgg==} - engines: {node: '>=18'} - hasBin: true - '@tailwindcss/forms@0.5.10': resolution: {integrity: sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==} peerDependencies: @@ -313,13 +308,13 @@ packages: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} - playwright-core@1.56.0: - resolution: {integrity: sha512-1SXl7pMfemAMSDn5rkPeZljxOCYAmQnYLBTExuh6E8USHXGSX3dx6lYZN/xPpTz1vimXmPA9CDnILvmJaB8aSQ==} + playwright-core@1.56.1: + resolution: {integrity: sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==} engines: {node: '>=18'} hasBin: true - playwright@1.56.0: - resolution: {integrity: sha512-X5Q1b8lOdWIE4KAoHpW3SE8HvUB+ZZsUoN64ZhjnN8dOb1UpujxBtENGiZFE+9F/yhzJwYa+ca3u43FeLbboHA==} + playwright@1.56.1: + resolution: {integrity: sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==} engines: {node: '>=18'} hasBin: true @@ -518,10 +513,6 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@playwright/test@1.56.0': - dependencies: - playwright: 1.56.0 - '@tailwindcss/forms@0.5.10(tailwindcss@3.4.18(yaml@2.5.0))': dependencies: mini-svg-data-uri: 1.4.4 @@ -734,11 +725,11 @@ snapshots: pirates@4.0.7: {} - playwright-core@1.56.0: {} + playwright-core@1.56.1: {} - playwright@1.56.0: + playwright@1.56.1: dependencies: - playwright-core: 1.56.0 + playwright-core: 1.56.1 optionalDependencies: fsevents: 2.3.2 From 5187353410d3ec8e99a57f14ba5c78f5c614edfa Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 12:01:42 +0000 Subject: [PATCH 086/158] wip --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2089c57..dce3e8c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -138,7 +138,7 @@ jobs: run: composer install --no-progress --prefer-dist --no-interaction - name: Run Pest tests - run: ./vendor/bin/pest --colors=always + run: ./vendor/bin/pest --colors=always --browser firefox - name: Upload test results if: always() From 1647b30cfa796b4bc520bd460525734678cd5385 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 12:27:41 +0000 Subject: [PATCH 087/158] wip --- .github/workflows/tests.yml | 4 ++++ tests/Browser/PluginSettingsTest.php | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index dce3e8c..b06a0a6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -33,6 +33,10 @@ jobs: --health-interval=10s --health-timeout=5s --health-retries=5 + web: + image: dunglas/frankenphp:1.9-php-${{ matrix.php }} + ports: + - "8100:80" env: WP_VERSION: ${{ matrix.wordpress }} diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 49e297f..7b6655f 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -9,6 +9,11 @@ const INACTIVE_ADMIN_COMMENT = ''; const NOSCRIPT_SELECTOR = 'noscript img[src="https://queue.simpleanalyticscdn.com/noscript.gif"][alt=""][referrerpolicy="no-referrer-when-downgrade"]'; +it('smthg',function (){ + visit('http://localhost:8100')->withLocale('en-GB'); +}); + +/* it('can be activated', function () { asAdmin() ->navigate('http://localhost:8100/wp-admin/plugins.php') @@ -195,4 +200,4 @@ ->assertValue('simpleanalytics_custom_domain', 'mydomain.com'); visit('http://localhost:8100')->assertPresent('script[src="https://mydomain.com/latest.js"]'); -}); +});*/ From e5ab0c71eab7fe4896d7c322e1151ffa2201e3da Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 12:28:22 +0000 Subject: [PATCH 088/158] wip --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b06a0a6..fff9ed2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -34,7 +34,7 @@ jobs: --health-timeout=5s --health-retries=5 web: - image: dunglas/frankenphp:1.9-php-${{ matrix.php }} + image: dunglas/frankenphp:1.9-php${{ matrix.php }} ports: - "8100:80" From e548cfeef2a4b098f8d818bfd577afc481d0bdde Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 13:19:42 +0000 Subject: [PATCH 089/158] wip --- .github/workflows/tests.yml | 6 ++++-- Caddyfile | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 Caddyfile diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fff9ed2..a1e6b1a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -35,8 +35,10 @@ jobs: --health-retries=5 web: image: dunglas/frankenphp:1.9-php${{ matrix.php }} - ports: - - "8100:80" + ports: [ 8100:80 ] + volumes: + - ./wordpress:/var/www/html + - ./Caddyfile:/etc/frankenphp/Caddyfile env: WP_VERSION: ${{ matrix.wordpress }} diff --git a/Caddyfile b/Caddyfile new file mode 100644 index 0000000..7923b0f --- /dev/null +++ b/Caddyfile @@ -0,0 +1,24 @@ +{ + local_certs + auto_https disable_redirects + + frankenphp { + #worker /path/to/your/worker.php + } + + order php_server before file_server + order php before file_server + order request_header before rewrite +} + +:80 { + @static { + file + path *.ico *.css *.js *.gif *.jpg *.jpeg *.png *.svg *.woff + } + + root * /var/www/html/ + encode br zstd gzip + + php_server +} From f4773532f7b76ba4e8beffcb316d61a75d0a9326 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 13:25:55 +0000 Subject: [PATCH 090/158] wip --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a1e6b1a..52dbdd4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -37,8 +37,8 @@ jobs: image: dunglas/frankenphp:1.9-php${{ matrix.php }} ports: [ 8100:80 ] volumes: - - ./wordpress:/var/www/html - - ./Caddyfile:/etc/frankenphp/Caddyfile + - $GITHUB_WORKSPACE/wordpress:/var/www/html + - $GITHUB_WORKSPACE/Caddyfile:/etc/frankenphp/Caddyfile env: WP_VERSION: ${{ matrix.wordpress }} From 950eee510e57ea9ddfee714f3b84dba16bde72c9 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 13:27:55 +0000 Subject: [PATCH 091/158] wip --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 52dbdd4..215fd95 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -37,8 +37,8 @@ jobs: image: dunglas/frankenphp:1.9-php${{ matrix.php }} ports: [ 8100:80 ] volumes: - - $GITHUB_WORKSPACE/wordpress:/var/www/html - - $GITHUB_WORKSPACE/Caddyfile:/etc/frankenphp/Caddyfile + - ${{ github.workspace }}/wordpress:/var/www/html + - ${{ github.workspace }}/Caddyfile:/etc/frankenphp/Caddyfile env: WP_VERSION: ${{ matrix.wordpress }} From 06c07224c5aab7bfa79c58bcda17265361449c76 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 13:29:05 +0000 Subject: [PATCH 092/158] wip --- .github/workflows/tests.yml | 2 +- Caddyfile => tests/Caddyfile | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename Caddyfile => tests/Caddyfile (100%) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 215fd95..3edb307 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -38,7 +38,7 @@ jobs: ports: [ 8100:80 ] volumes: - ${{ github.workspace }}/wordpress:/var/www/html - - ${{ github.workspace }}/Caddyfile:/etc/frankenphp/Caddyfile + - ${{ github.workspace }}/tests:/etc/frankenphp/ env: WP_VERSION: ${{ matrix.wordpress }} diff --git a/Caddyfile b/tests/Caddyfile similarity index 100% rename from Caddyfile rename to tests/Caddyfile From 94cd4d730a97a09a245bc5ae1197b2e6276f34c9 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 13:32:08 +0000 Subject: [PATCH 093/158] wip --- .github/workflows/tests.yml | 23 ++++++++++++++++++++++- tests/Caddyfile | 24 ------------------------ 2 files changed, 22 insertions(+), 25 deletions(-) delete mode 100644 tests/Caddyfile diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3edb307..42b896d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -36,9 +36,30 @@ jobs: web: image: dunglas/frankenphp:1.9-php${{ matrix.php }} ports: [ 8100:80 ] + env: + FRANKENPHP_CONFIG: >- + { + local_certs + auto_https off + frankenphp { + #worker /path/to/your/worker.php + } + order php_server before file_server + order php before file_server + order request_header before rewrite + } + + :80 { + @static { + file + path *.ico *.css *.js *.gif *.jpg *.jpeg *.png *.svg *.woff + } + root * /var/www/html/ + encode br zstd gzip + php_server + } volumes: - ${{ github.workspace }}/wordpress:/var/www/html - - ${{ github.workspace }}/tests:/etc/frankenphp/ env: WP_VERSION: ${{ matrix.wordpress }} diff --git a/tests/Caddyfile b/tests/Caddyfile deleted file mode 100644 index 7923b0f..0000000 --- a/tests/Caddyfile +++ /dev/null @@ -1,24 +0,0 @@ -{ - local_certs - auto_https disable_redirects - - frankenphp { - #worker /path/to/your/worker.php - } - - order php_server before file_server - order php before file_server - order request_header before rewrite -} - -:80 { - @static { - file - path *.ico *.css *.js *.gif *.jpg *.jpeg *.png *.svg *.woff - } - - root * /var/www/html/ - encode br zstd gzip - - php_server -} From c52dbd3b28d60c08b3214b05faa290b696ecc8d5 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 13:35:37 +0000 Subject: [PATCH 094/158] wip --- .github/workflows/tests.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 42b896d..85d959c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -41,14 +41,11 @@ jobs: { local_certs auto_https off - frankenphp { - #worker /path/to/your/worker.php - } + frankenphp order php_server before file_server order php before file_server order request_header before rewrite } - :80 { @static { file From e4ec3c78047134992d5e8b8c5b37a0777996d569 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 13:38:42 +0000 Subject: [PATCH 095/158] wip --- .github/workflows/tests.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 85d959c..447354c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -39,21 +39,21 @@ jobs: env: FRANKENPHP_CONFIG: >- { - local_certs - auto_https off - frankenphp - order php_server before file_server - order php before file_server - order request_header before rewrite + local_certs + auto_https off + frankenphp + order php_server before file_server + order php before file_server + order request_header before rewrite } :80 { - @static { - file - path *.ico *.css *.js *.gif *.jpg *.jpeg *.png *.svg *.woff - } - root * /var/www/html/ - encode br zstd gzip - php_server + @static { + file + path *.ico *.css *.js *.gif *.jpg *.jpeg *.png *.svg *.woff + } + root * /var/www/html/ + encode br zstd gzip + php_server } volumes: - ${{ github.workspace }}/wordpress:/var/www/html From 5f850c8c4706fc2d843d81b1a1e33e4fa490ede0 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 13:39:05 +0000 Subject: [PATCH 096/158] wip --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 447354c..01fdad9 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -37,7 +37,7 @@ jobs: image: dunglas/frankenphp:1.9-php${{ matrix.php }} ports: [ 8100:80 ] env: - FRANKENPHP_CONFIG: >- + FRANKENPHP_CONFIG: | { local_certs auto_https off From 01e2e8e092314a9a4cbdbfb19d475b88881cf0c7 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 13:41:58 +0000 Subject: [PATCH 097/158] wip --- .github/workflows/tests.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 01fdad9..4923796 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -47,10 +47,6 @@ jobs: order request_header before rewrite } :80 { - @static { - file - path *.ico *.css *.js *.gif *.jpg *.jpeg *.png *.svg *.woff - } root * /var/www/html/ encode br zstd gzip php_server From ee823a94c6c41c0066a7f747dd3a331aa6892e6c Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 13:44:04 +0000 Subject: [PATCH 098/158] wip --- .github/workflows/tests.yml | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4923796..367bd09 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -35,18 +35,10 @@ jobs: --health-retries=5 web: image: dunglas/frankenphp:1.9-php${{ matrix.php }} - ports: [ 8100:80 ] + ports: [ 8100:8100 ] env: FRANKENPHP_CONFIG: | - { - local_certs - auto_https off - frankenphp - order php_server before file_server - order php before file_server - order request_header before rewrite - } - :80 { + localhost:8100 { root * /var/www/html/ encode br zstd gzip php_server From 062cee28e16a473d6024955398d55c9d35c1c16a Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 13:45:54 +0000 Subject: [PATCH 099/158] wip --- .github/workflows/tests.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 367bd09..b0ce28f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -38,11 +38,11 @@ jobs: ports: [ 8100:8100 ] env: FRANKENPHP_CONFIG: | - localhost:8100 { - root * /var/www/html/ - encode br zstd gzip - php_server - } + localhost:8100 + + root * /var/www/html/ + encode br zstd gzip + php_server volumes: - ${{ github.workspace }}/wordpress:/var/www/html From 288af21e72e13d4490fbdddb5a1cc5962422e098 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 13:48:22 +0000 Subject: [PATCH 100/158] wip --- .github/workflows/tests.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b0ce28f..c43a9da 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -37,12 +37,7 @@ jobs: image: dunglas/frankenphp:1.9-php${{ matrix.php }} ports: [ 8100:8100 ] env: - FRANKENPHP_CONFIG: | - localhost:8100 - - root * /var/www/html/ - encode br zstd gzip - php_server + SERVER_ROOT: /var/www/html volumes: - ${{ github.workspace }}/wordpress:/var/www/html From 02c4a15eec695490859c92052122e4266ad6dad1 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 13:48:52 +0000 Subject: [PATCH 101/158] wip --- .github/workflows/tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c43a9da..bfd3bfc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -38,6 +38,7 @@ jobs: ports: [ 8100:8100 ] env: SERVER_ROOT: /var/www/html + SERVER_NAME: localhost:8100 volumes: - ${{ github.workspace }}/wordpress:/var/www/html From 8bd3b9a9efee47120150f024314deb5932c30e2c Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 13:50:48 +0000 Subject: [PATCH 102/158] wip --- .github/workflows/tests.yml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index bfd3bfc..3eb1b68 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -107,19 +107,6 @@ jobs: PLUGIN_SLUG=$(basename "$GITHUB_WORKSPACE") ln -s "$GITHUB_WORKSPACE" "wordpress/wp-content/plugins/simpleanalytics" - - name: Start WordPress server - run: | - wp server --host=localhost --port=8100 --allow-root --path=wordpress > /tmp/wp-server.log 2>&1 & - # Health check - for i in {1..30}; do - if curl -sf http://localhost:8100/wp-login.php > /dev/null 2>&1; then - echo "WordPress server ready" - break - fi - [ $i -eq 30 ] && echo "Server failed to start" && cat /tmp/wp-server.log && exit 1 - sleep 1 - done - - name: Install pnpm uses: pnpm/action-setup@v4 with: From a2712ab4313324f76cca931a8cc7393c63af5a44 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 13:52:33 +0000 Subject: [PATCH 103/158] wip --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3eb1b68..f1604a2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -38,7 +38,7 @@ jobs: ports: [ 8100:8100 ] env: SERVER_ROOT: /var/www/html - SERVER_NAME: localhost:8100 + SERVER_NAME: http://localhost:8100 volumes: - ${{ github.workspace }}/wordpress:/var/www/html From 26333c7e4c655530b63522dc2bb363997327e8ae Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 13:53:10 +0000 Subject: [PATCH 104/158] wip --- tests/Browser/PluginSettingsTest.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 7b6655f..49e297f 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -9,11 +9,6 @@ const INACTIVE_ADMIN_COMMENT = ''; const NOSCRIPT_SELECTOR = 'noscript img[src="https://queue.simpleanalyticscdn.com/noscript.gif"][alt=""][referrerpolicy="no-referrer-when-downgrade"]'; -it('smthg',function (){ - visit('http://localhost:8100')->withLocale('en-GB'); -}); - -/* it('can be activated', function () { asAdmin() ->navigate('http://localhost:8100/wp-admin/plugins.php') @@ -200,4 +195,4 @@ ->assertValue('simpleanalytics_custom_domain', 'mydomain.com'); visit('http://localhost:8100')->assertPresent('script[src="https://mydomain.com/latest.js"]'); -});*/ +}); From d810ec3a29ca01c003b4673f24b97b485d88d032 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 13:59:30 +0000 Subject: [PATCH 105/158] wip --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f1604a2..e5eaaa7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -38,7 +38,7 @@ jobs: ports: [ 8100:8100 ] env: SERVER_ROOT: /var/www/html - SERVER_NAME: http://localhost:8100 + SERVER_NAME: http://0.0.0.0:8100 volumes: - ${{ github.workspace }}/wordpress:/var/www/html From 1f8eca8ecc7edffb6ff51dab91ff5ee2b7a3f5d0 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 14:29:09 +0000 Subject: [PATCH 106/158] wip --- .github/workflows/tests.yml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e5eaaa7..6f6e349 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -33,14 +33,6 @@ jobs: --health-interval=10s --health-timeout=5s --health-retries=5 - web: - image: dunglas/frankenphp:1.9-php${{ matrix.php }} - ports: [ 8100:8100 ] - env: - SERVER_ROOT: /var/www/html - SERVER_NAME: http://0.0.0.0:8100 - volumes: - - ${{ github.workspace }}/wordpress:/var/www/html env: WP_VERSION: ${{ matrix.wordpress }} @@ -76,6 +68,15 @@ jobs: tar -xzf wordpress-${WP_VERSION}.tar.gz rm wordpress-${WP_VERSION}.tar.gz + - name: Start FrankenPHP server + run: | + docker run -d \ + --name frankenphp \ + -p 8100:8100 \ + -v $GITHUB_WORKSPACE/wordpress:/var/www/html \ + -v $GITHUB_WORKSPACE/Caddyfile:/etc/frankenphp/Caddyfile \ + dunglas/frankenphp:1.9-php${{ matrix.php }} + - name: Install WordPress run: | rm -f wordpress/wp-config.php From ab35e0835cf01389ec17156c843b4a6b701fa94e Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 14:30:02 +0000 Subject: [PATCH 107/158] wip --- Caddyfile | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Caddyfile diff --git a/Caddyfile b/Caddyfile new file mode 100644 index 0000000..ea80992 --- /dev/null +++ b/Caddyfile @@ -0,0 +1,18 @@ +{ + local_certs + auto_https off + frankenphp + order php_server before file_server + order php before file_server + order request_header before rewrite +} + +:80 { + @static { + file + path *.ico *.css *.js *.gif *.jpg *.jpeg *.png *.svg *.woff + } + root * /var/www/html/ + encode br zstd gzip + php_server +} From d32b46e2f37820c7b93c0b3eabd986ff8c617928 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 14:35:46 +0000 Subject: [PATCH 108/158] wip --- Caddyfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Caddyfile b/Caddyfile index ea80992..f186015 100644 --- a/Caddyfile +++ b/Caddyfile @@ -7,7 +7,7 @@ order request_header before rewrite } -:80 { +0.0.0.0:80 { @static { file path *.ico *.css *.js *.gif *.jpg *.jpeg *.png *.svg *.woff From c4f3d91355389fcd62c29f9e811878277b50d0a2 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 14:35:57 +0000 Subject: [PATCH 109/158] wip --- Caddyfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Caddyfile b/Caddyfile index f186015..7621c00 100644 --- a/Caddyfile +++ b/Caddyfile @@ -7,7 +7,7 @@ order request_header before rewrite } -0.0.0.0:80 { +0.0.0.0:8100 { @static { file path *.ico *.css *.js *.gif *.jpg *.jpeg *.png *.svg *.woff From faa0ae253e7fd94be17d0823dcabfbda1f05f65a Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 14:36:02 +0000 Subject: [PATCH 110/158] wip --- Caddyfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Caddyfile b/Caddyfile index 7621c00..8ce5706 100644 --- a/Caddyfile +++ b/Caddyfile @@ -7,7 +7,7 @@ order request_header before rewrite } -0.0.0.0:8100 { +:8100 { @static { file path *.ico *.css *.js *.gif *.jpg *.jpeg *.png *.svg *.woff From afd5ccb4a84362c3c68e91ce9d36dfc0ecfd15c6 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 14:47:40 +0000 Subject: [PATCH 111/158] docker build --- .github/docker/Dockerfile | 22 ++++++++++++++++++++++ .github/workflows/tests.yml | 15 ++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 .github/docker/Dockerfile diff --git a/.github/docker/Dockerfile b/.github/docker/Dockerfile new file mode 100644 index 0000000..462c2da --- /dev/null +++ b/.github/docker/Dockerfile @@ -0,0 +1,22 @@ +ARG PHP_VERSION=8.4 +FROM dunglas/frankenphp:1.9-php${PHP_VERSION} + +RUN install-php-extensions \ + bcmath \ + exif \ + gd \ + intl \ + mbstring \ + mysqli \ + opcache \ + pdo_mysql \ + zip \ + curl \ + xml \ + dom \ + simplexml \ + tokenizer \ + json \ + fileinfo \ + sockets \ + imagick diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6f6e349..385e770 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -68,6 +68,19 @@ jobs: tar -xzf wordpress-${WP_VERSION}.tar.gz rm wordpress-${WP_VERSION}.tar.gz + - name: Build FrankenPHP image (with cache) + id: build + uses: docker/build-push-action@v6 + with: + context: . + file: .github/docker/Dockerfile + tags: frankenphp-${{ matrix.php }} + load: true + build-args: | + PHP_VERSION=${{ matrix.php }} + cache-from: type=gha + cache-to: type=gha,mode=max + - name: Start FrankenPHP server run: | docker run -d \ @@ -75,7 +88,7 @@ jobs: -p 8100:8100 \ -v $GITHUB_WORKSPACE/wordpress:/var/www/html \ -v $GITHUB_WORKSPACE/Caddyfile:/etc/frankenphp/Caddyfile \ - dunglas/frankenphp:1.9-php${{ matrix.php }} + frankenphp-${{ matrix.php }} - name: Install WordPress run: | From 8fae52392ff50dcffcbe10a9e07027c9c8c313f2 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 14:49:19 +0000 Subject: [PATCH 112/158] docker build --- .github/workflows/tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 385e770..fc325ae 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -68,6 +68,9 @@ jobs: tar -xzf wordpress-${WP_VERSION}.tar.gz rm wordpress-${WP_VERSION}.tar.gz + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Build FrankenPHP image (with cache) id: build uses: docker/build-push-action@v6 From db5b27d0699535e0008d9d64a2a2a99f4f63545c Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 15:00:51 +0000 Subject: [PATCH 113/158] docker build --- .github/workflows/tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fc325ae..0e1c625 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -88,6 +88,7 @@ jobs: run: | docker run -d \ --name frankenphp \ + --network host \ -p 8100:8100 \ -v $GITHUB_WORKSPACE/wordpress:/var/www/html \ -v $GITHUB_WORKSPACE/Caddyfile:/etc/frankenphp/Caddyfile \ From 73f8597bd03fae3b6c9d8111295bf59d27b7a4b7 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 15:12:31 +0000 Subject: [PATCH 114/158] docker build --- .github/workflows/tests.yml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0e1c625..989689f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -64,8 +64,9 @@ jobs: - name: Download WordPress if: steps.cache-wordpress.outputs.cache-hit != 'true' run: | + mkdir -p /tmp/wp curl -O https://wordpress.org/wordpress-${WP_VERSION}.tar.gz - tar -xzf wordpress-${WP_VERSION}.tar.gz + tar -xzf wordpress-${WP_VERSION}.tar.gz --strip-components=1 -C /tmp/wp rm wordpress-${WP_VERSION}.tar.gz - name: Set up Docker Buildx @@ -90,7 +91,8 @@ jobs: --name frankenphp \ --network host \ -p 8100:8100 \ - -v $GITHUB_WORKSPACE/wordpress:/var/www/html \ + -v /tmp/wp:/var/www/html \ + -v $GITHUB_WORKSPACE:/var/www/html/wp-content/plugins/simpleanalytics \ -v $GITHUB_WORKSPACE/Caddyfile:/etc/frankenphp/Caddyfile \ frankenphp-${{ matrix.php }} @@ -102,7 +104,7 @@ jobs: --dbuser="$WP_DB_USER" \ --dbpass="$WP_DB_PASS" \ --dbhost="$WP_DB_HOST" \ - --path=wordpress \ + --path=/tmp/wp \ --skip-check wp core install \ --url="${WP_SITE_URL}" \ @@ -110,15 +112,15 @@ jobs: --admin_user=admin \ --admin_password=admin \ --admin_email=test@example.com \ - --path=wordpress \ + --path=/tmp/wp \ --skip-email \ --allow-root - wp user create author author@local.test --role=author --user_pass=author --path=wordpress - wp user create editor editor@local.test --role=editor --user_pass=editor --path=wordpress - wp user create subscriber subscriber@local.test --role=subscriber --user_pass=subscriber --path=wordpress + wp user create author author@local.test --role=author --user_pass=author --path=/tmp/wp + wp user create editor editor@local.test --role=editor --user_pass=editor --path=/tmp/wp + wp user create subscriber subscriber@local.test --role=subscriber --user_pass=subscriber --path=/tmp/wp - name: Show current config values - run: wp config list --path=wordpress --allow-root + run: wp config list --path=/tmp/wp --allow-root - name: Install plugin run: | From 56fb7a290090abe0a2835772a5075954a16025fa Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 15:16:01 +0000 Subject: [PATCH 115/158] docker build --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 989689f..54fa118 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -58,7 +58,7 @@ jobs: id: cache-wordpress uses: actions/cache@v3 with: - path: wordpress + path: /tmp/wp key: wp-${{ matrix.wordpress }} - name: Download WordPress @@ -98,7 +98,7 @@ jobs: - name: Install WordPress run: | - rm -f wordpress/wp-config.php + rm -f /tmp/wp/wp-config.php wp config create \ --dbname="$WP_DB_NAME" \ --dbuser="$WP_DB_USER" \ From 3e6bf96b069bedddf31565db0da6f5716f083c38 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 15:17:30 +0000 Subject: [PATCH 116/158] docker build --- .github/workflows/tests.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 54fa118..0f7f3c6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -122,11 +122,6 @@ jobs: - name: Show current config values run: wp config list --path=/tmp/wp --allow-root - - name: Install plugin - run: | - PLUGIN_SLUG=$(basename "$GITHUB_WORKSPACE") - ln -s "$GITHUB_WORKSPACE" "wordpress/wp-content/plugins/simpleanalytics" - - name: Install pnpm uses: pnpm/action-setup@v4 with: From 06b6b475e7f32f81c87df4762822b0e47e9dd7ca Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 15:20:25 +0000 Subject: [PATCH 117/158] docker build --- .github/workflows/tests.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0f7f3c6..537ab2a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -49,7 +49,9 @@ jobs: - name: Set up PHP uses: shivammathur/setup-php@v2 with: - php-version: ${{ matrix.php }} + # Note: Specified version is only for running tests, + # as the WordPress PHP version is set inside the FrankenPHP Dockerfile. + php-version: 8.4 extensions: mysqli, zip, gd coverage: none tools: wp-cli From 35abb786867978eac8134ab3f88eb40fd4158ef1 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 15:23:23 +0000 Subject: [PATCH 118/158] wip --- .github/workflows/tests.yml | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 537ab2a..fcf564e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -150,7 +150,7 @@ jobs: run: composer install --no-progress --prefer-dist --no-interaction - name: Run Pest tests - run: ./vendor/bin/pest --colors=always --browser firefox + run: ./vendor/bin/pest --bail --colors=always - name: Upload test results if: always() diff --git a/package.json b/package.json index 0a84bbd..17da06f 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "scripts": { "dev": "tailwindcss -i resources/css/settings.css -o build/css/settings.css --watch", "build": "tailwindcss build -i resources/css/settings.css -o build/css/settings.css", - "tests:install": "playwright install --with-deps firefox", + "tests:install": "playwright install --with-deps chromium", "tests": "playwright test" }, "devDependencies": { From 431244bfbb3c14131e71916b7b97f0ee0fa3eca1 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 15:27:27 +0000 Subject: [PATCH 119/158] wip --- tests/Browser/PluginSettingsTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 49e297f..462d3a8 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -87,14 +87,14 @@ visit('http://localhost:8100')->assertSourceHas('data-auto-collect="true"'); }); -it('adds noscript tag when support no javascript mode is enabled', function () { +/*it('adds noscript tag when support no javascript mode is enabled', function () { asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') ->check('simpleanalytics_noscript') ->click('Save Changes') ->assertChecked('simpleanalytics_noscript'); visit('http://localhost:8100')->assertPresent(NOSCRIPT_SELECTOR); -}); +});*/ it('adds a script with onload callback', function () { asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') From 5116c3293081b3eb62575fa48e19117aa416b683 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 15:30:28 +0000 Subject: [PATCH 120/158] wip --- tests/Browser/PluginSettingsTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 462d3a8..7cb57d3 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -96,14 +96,14 @@ visit('http://localhost:8100')->assertPresent(NOSCRIPT_SELECTOR); });*/ -it('adds a script with onload callback', function () { +/*it('adds a script with onload callback', function () { asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') ->fill('simpleanalytics_onload_callback', 'sa_event("My event")') ->click('Save Changes') ->assertValue('simpleanalytics_onload_callback', 'sa_event("My event")'); visit('http://localhost:8100')->assertSourceHas('data-onload="sa_event(\"My event\")"'); -}); +});*/ it('adds a script with overwrite domain name', function () { asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') From 808c0e8a81cfab25876e59027017c67154c01f59 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 15:37:13 +0000 Subject: [PATCH 121/158] wip --- .github/workflows/tests.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fcf564e..7a6868e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,11 +11,8 @@ jobs: strategy: fail-fast: false matrix: - # temporary disabled for testing - # php: [ '7.4', '8.0', '8.1', '8.2' ] - # wordpress: [ '5.9', '6.0', '6.3', '6.5.3' ] - php: [ '8.4' ] - wordpress: [ '6.5' ] + php: [ '7.4', '8.0', '8.1', '8.2' ] + wordpress: [ '5.9', '6.0', '6.3', '6.5.3' ] exclude: # Exclude older PHP versions with newer WordPress - php: '7.4' From c78b773efa604a626d7df7058931a6b9fa578e37 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 15:40:12 +0000 Subject: [PATCH 122/158] wip --- .github/workflows/tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7a6868e..de3c0b7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,7 +11,8 @@ jobs: strategy: fail-fast: false matrix: - php: [ '7.4', '8.0', '8.1', '8.2' ] +# php: [ '7.4', '8.0', '8.1', '8.2' ] + php: [ '8.2', '8.3', '8.4' ] wordpress: [ '5.9', '6.0', '6.3', '6.5.3' ] exclude: # Exclude older PHP versions with newer WordPress From f4a529130d2d5982d7ad2123966861bbd0610ed2 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 16:42:48 +0000 Subject: [PATCH 123/158] wip --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index de3c0b7..79d2aca 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -148,7 +148,7 @@ jobs: run: composer install --no-progress --prefer-dist --no-interaction - name: Run Pest tests - run: ./vendor/bin/pest --bail --colors=always + run: ./vendor/bin/pest -v --bail --colors=always - name: Upload test results if: always() From 5e2c9d204b51b8c5f2eb5729eb6cf0ad2c08e0b6 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 17:07:54 +0000 Subject: [PATCH 124/158] wip --- tests/Browser/PluginSettingsTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 7cb57d3..3211799 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -35,9 +35,10 @@ ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules') ->fill('simpleanalytics_ignore_pages', '/vouchers') ->click('Save Changes') - ->assertValue('simpleanalytics_ignore_pages', '/vouchers'); + ->assertValue('simpleanalytics_ignore_pages', '/vouchers') + ->screenshot(); - visit('http://localhost:8100')->assertSourceHas('data-ignore-pages="/vouchers"'); + visit('http://localhost:8100')->dd()->assertSourceHas('data-ignore-pages="/vouchers"'); }); it('adds inactive script for selected user roles', function () { From eb52920628ea9a0b03a7a89076b4c14ee8f0fb7a Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 17:21:50 +0000 Subject: [PATCH 125/158] wip --- tests/Browser/PluginSettingsTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 3211799..93eb386 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -12,11 +12,11 @@ it('can be activated', function () { asAdmin() ->navigate('http://localhost:8100/wp-admin/plugins.php') - ->screenshot() ->assertPresent('tr[data-slug="simpleanalytics"]') ->click('#activate-simpleanalytics') ->assertPresent('a[href="options-general.php?page=simpleanalytics"]') - ->assertPresent('#deactivate-simpleanalytics'); + ->assertPresent('#deactivate-simpleanalytics') + ->screenshot(); }); it('adds a script by default', function () { @@ -38,7 +38,7 @@ ->assertValue('simpleanalytics_ignore_pages', '/vouchers') ->screenshot(); - visit('http://localhost:8100')->dd()->assertSourceHas('data-ignore-pages="/vouchers"'); + visit('http://localhost:8100')->refresh()->assertSourceHas('data-ignore-pages="/vouchers"'); }); it('adds inactive script for selected user roles', function () { From fc5f5ba9d50a7de341399216b29c702ebc03275e Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 17:22:03 +0000 Subject: [PATCH 126/158] wip --- tests/Browser/PluginSettingsTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 93eb386..06ff4ad 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -35,6 +35,7 @@ ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules') ->fill('simpleanalytics_ignore_pages', '/vouchers') ->click('Save Changes') + ->refresh() ->assertValue('simpleanalytics_ignore_pages', '/vouchers') ->screenshot(); From cb53fbf471bd53e3b363e80394c10f9cfe9feec8 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 17:36:57 +0000 Subject: [PATCH 127/158] wip --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 79d2aca..c942b1a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,7 +13,7 @@ jobs: matrix: # php: [ '7.4', '8.0', '8.1', '8.2' ] php: [ '8.2', '8.3', '8.4' ] - wordpress: [ '5.9', '6.0', '6.3', '6.5.3' ] + wordpress: [ '5.9', '6.0', '6.3', '6.7', '6.8' ] exclude: # Exclude older PHP versions with newer WordPress - php: '7.4' From 01e510721a407901d4f7615b29538be660387fdb Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 17:42:55 +0000 Subject: [PATCH 128/158] wip --- .github/workflows/tests.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c942b1a..2891235 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,7 +11,7 @@ jobs: strategy: fail-fast: false matrix: -# php: [ '7.4', '8.0', '8.1', '8.2' ] + # php: [ '7.4', '8.0', '8.1', '8.2' ] php: [ '8.2', '8.3', '8.4' ] wordpress: [ '5.9', '6.0', '6.3', '6.7', '6.8' ] exclude: @@ -41,6 +41,14 @@ jobs: WP_DB_HOST: 127.0.0.1 steps: + - name: Check MySQL tables + run: | + echo "Listing databases:" + mysql -h 127.0.0.1 -uroot -proot -e "SHOW DATABASES;" + + echo "Checking if 'wordpress' database has any tables:" + mysql -h 127.0.0.1 -uroot -proot -D wordpress -e "SHOW TABLES;" || echo "No tables found (yet)." + - name: Checkout plugin uses: actions/checkout@v4 From 1f0fe035caea2de9b336b715f52907cde43714f5 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 17:56:27 +0000 Subject: [PATCH 129/158] wip --- .github/workflows/tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2891235..afe218b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -83,6 +83,8 @@ jobs: - name: Build FrankenPHP image (with cache) id: build uses: docker/build-push-action@v6 + env: + DOCKER_BUILD_SUMMARY: false with: context: . file: .github/docker/Dockerfile From 327ec18053fb6d6bbaefe281ebd0c052dbfa9ae3 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 17:57:46 +0000 Subject: [PATCH 130/158] wip --- .github/workflows/tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index afe218b..eeab5fd 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,7 +13,8 @@ jobs: matrix: # php: [ '7.4', '8.0', '8.1', '8.2' ] php: [ '8.2', '8.3', '8.4' ] - wordpress: [ '5.9', '6.0', '6.3', '6.7', '6.8' ] + # wordpress: [ '5.9', '6.0', '6.3', '6.7', '6.8' ] + wordpress: [ '6.7', '6.8' ] exclude: # Exclude older PHP versions with newer WordPress - php: '7.4' From 39264aca18314eee737b3bc495155485c92d6e60 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sat, 1 Nov 2025 18:24:24 +0000 Subject: [PATCH 131/158] wip --- tests/Browser/PluginSettingsTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 06ff4ad..4e9200a 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -11,6 +11,7 @@ it('can be activated', function () { asAdmin() + ->wait(2) ->navigate('http://localhost:8100/wp-admin/plugins.php') ->assertPresent('tr[data-slug="simpleanalytics"]') ->click('#activate-simpleanalytics') From 7bf690d5b6c70c4c3f509d75e64c5c588c0c31c4 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sun, 2 Nov 2025 16:08:36 +0000 Subject: [PATCH 132/158] wip --- .github/workflows/tests.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index eeab5fd..929d42b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -170,8 +170,8 @@ jobs: tests/Browser/Screenshots retention-days: 30 - - name: Debug server status - if: failure() + - name: Show FrankenPHP logs + if: always() run: | - cat /tmp/wp-server.log || echo "No log file found" - ps aux | grep php || true + echo "=== FrankenPHP logs ===" + docker logs frankenphp || echo "No logs found" From 08255f531fc9a2eaef1a6e068330fe05848df313 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sun, 2 Nov 2025 16:12:50 +0000 Subject: [PATCH 133/158] wip --- Caddyfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Caddyfile b/Caddyfile index 8ce5706..a7f9300 100644 --- a/Caddyfile +++ b/Caddyfile @@ -15,4 +15,6 @@ root * /var/www/html/ encode br zstd gzip php_server + output stdout + format json } From fa6d90d3f65e43344ba66e26b076f94aa33439ea Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sun, 2 Nov 2025 16:13:49 +0000 Subject: [PATCH 134/158] inc timeout --- tests/Pest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Pest.php b/tests/Pest.php index 3105897..57a92cd 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -16,6 +16,7 @@ use Pest\Browser\Api\Webpage; pest()->extend(TestCase::class)->in('Feature'); +pest()->browser()->timeout(10000); /* |-------------------------------------------------------------------------- From dc5c6b902536003046421d6791bd6545ef75ebf5 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sun, 2 Nov 2025 16:16:43 +0000 Subject: [PATCH 135/158] wip --- Caddyfile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Caddyfile b/Caddyfile index a7f9300..e991953 100644 --- a/Caddyfile +++ b/Caddyfile @@ -15,6 +15,8 @@ root * /var/www/html/ encode br zstd gzip php_server - output stdout - format json + log { + output stdout + format json + } } From 4b42108c066a91efc8273e31746da05e191b3c4a Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sun, 2 Nov 2025 16:22:22 +0000 Subject: [PATCH 136/158] wip --- Caddyfile | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Caddyfile b/Caddyfile index e991953..b76007b 100644 --- a/Caddyfile +++ b/Caddyfile @@ -15,8 +15,5 @@ root * /var/www/html/ encode br zstd gzip php_server - log { - output stdout - format json - } + log } From 7f50e147a6b27df7d3d59cbaed41e2db58cbabac Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sun, 2 Nov 2025 16:28:59 +0000 Subject: [PATCH 137/158] wip --- Caddyfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Caddyfile b/Caddyfile index b76007b..aada23e 100644 --- a/Caddyfile +++ b/Caddyfile @@ -15,5 +15,7 @@ root * /var/www/html/ encode br zstd gzip php_server - log + log { + format structure + } } From a1aeb6e9ef42a17388a2d13e7591b132af0a77e8 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sun, 2 Nov 2025 16:31:11 +0000 Subject: [PATCH 138/158] wip --- Caddyfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Caddyfile b/Caddyfile index aada23e..8d77d45 100644 --- a/Caddyfile +++ b/Caddyfile @@ -16,6 +16,6 @@ encode br zstd gzip php_server log { - format structure + format console } } From 8e4229a88f9bdfb407ceca4c556ed6c5df4be806 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sun, 2 Nov 2025 16:51:54 +0000 Subject: [PATCH 139/158] wip --- tests/Browser/PluginSettingsTest.php | 1 - tests/Pest.php | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 4e9200a..06ff4ad 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -11,7 +11,6 @@ it('can be activated', function () { asAdmin() - ->wait(2) ->navigate('http://localhost:8100/wp-admin/plugins.php') ->assertPresent('tr[data-slug="simpleanalytics"]') ->click('#activate-simpleanalytics') diff --git a/tests/Pest.php b/tests/Pest.php index 57a92cd..dbdc073 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -16,7 +16,7 @@ use Pest\Browser\Api\Webpage; pest()->extend(TestCase::class)->in('Feature'); -pest()->browser()->timeout(10000); +pest()->browser()->timeout(20000); /* |-------------------------------------------------------------------------- From 95d9c0ebf881ee1fe28a531cf6e7d3e609913e61 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sun, 2 Nov 2025 16:57:52 +0000 Subject: [PATCH 140/158] wip --- tests/Pest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Pest.php b/tests/Pest.php index dbdc073..c9a53fa 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -16,7 +16,7 @@ use Pest\Browser\Api\Webpage; pest()->extend(TestCase::class)->in('Feature'); -pest()->browser()->timeout(20000); +pest()->browser()->timeout(180000); /* |-------------------------------------------------------------------------- From 0a7abed6607c6fa3985cb30ef513433995404586 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Sun, 2 Nov 2025 17:09:02 +0000 Subject: [PATCH 141/158] wip --- Caddyfile | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Caddyfile b/Caddyfile index 8d77d45..92bddef 100644 --- a/Caddyfile +++ b/Caddyfile @@ -2,16 +2,14 @@ local_certs auto_https off frankenphp - order php_server before file_server - order php before file_server - order request_header before rewrite } :8100 { @static { file - path *.ico *.css *.js *.gif *.jpg *.jpeg *.png *.svg *.woff + path *.avif *.ico *.css *.js *.gif *.jpg *.jpeg *.png *.svg *.woff *.woff2 *.gpx } + header @static Cache-Control max-age=5184000 root * /var/www/html/ encode br zstd gzip php_server From 407f598b1c0f8f9a2400255737a9c0ee000e0728 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Mon, 3 Nov 2025 14:57:06 +0000 Subject: [PATCH 142/158] move from pestphp to zenstruck/browser --- .github/workflows/tests.yml | 10 +- .gitignore | 15 +- composer.json | 8 +- composer.lock | 5967 +++++++++++--------------- phpunit.xml | 12 +- tests/Browser/BrowserTestCase.php | 36 + tests/Browser/PluginSettingsTest.php | 212 +- tests/Pest.php | 69 - tests/TestCase.php | 1 - tests/TestKernel.php | 24 + 10 files changed, 2551 insertions(+), 3803 deletions(-) create mode 100644 tests/Browser/BrowserTestCase.php delete mode 100644 tests/Pest.php create mode 100644 tests/TestKernel.php diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 929d42b..5dd5218 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -144,10 +144,8 @@ jobs: node-version: lts/* cache: "pnpm" - - name: Install Playwright and dependencies - run: | - pnpm install - pnpm run tests:install + - name: Install pnpm dependencies + run: pnpm install - name: Cache composer dependencies uses: actions/cache@v3 @@ -156,10 +154,10 @@ jobs: key: composer-${{ hashFiles('composer.lock') }} - name: Run composer install - run: composer install --no-progress --prefer-dist --no-interaction + run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist - name: Run Pest tests - run: ./vendor/bin/pest -v --bail --colors=always + run: ./vendor/bin/phpunit - name: Upload test results if: always() diff --git a/.gitignore b/.gitignore index 353c019..cf492a0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,8 @@ .svn -node* -vendor* build - -# Playwright +vendor/ node_modules/ -/test-results/ -/playwright-report/ -/blob-report/ -/playwright/.cache/ -tests-browser-state.json -tests/**/Screenshots +.phpunit.result.cache +var +drivers +driver diff --git a/composer.json b/composer.json index f0a14a1..144e66a 100644 --- a/composer.json +++ b/composer.json @@ -1,9 +1,11 @@ { "require-dev": { "rector/rector": "^1.2", - "pestphp/pest": "^4.1", - "pestphp/pest-plugin-browser": "^4.1", - "symfony/var-dumper": "^7.3" + "symfony/var-dumper": "^7.3", + "zenstruck/browser": "^1.9", + "phpunit/phpunit": "^12", + "symfony/panther": "^2.2", + "dbrekelmans/bdi": "^1.4" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index a90792d..fba7461 100644 --- a/composer.lock +++ b/composer.lock @@ -4,41 +4,49 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f021bcb880511a080c31806eb76e1619", + "content-hash": "3c6e2e36603819c55446fde44c2a1fe1", "packages": [], "packages-dev": [ { - "name": "amphp/amp", - "version": "v3.1.1", + "name": "behat/mink", + "version": "v1.12.0", "source": { "type": "git", - "url": "https://github.com/amphp/amp.git", - "reference": "fa0ab33a6f47a82929c38d03ca47ebb71086a93f" + "url": "https://github.com/minkphp/Mink.git", + "reference": "7e4edec6c335937029cb3569ce7ef81182804d0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/amp/zipball/fa0ab33a6f47a82929c38d03ca47ebb71086a93f", - "reference": "fa0ab33a6f47a82929c38d03ca47ebb71086a93f", + "url": "https://api.github.com/repos/minkphp/Mink/zipball/7e4edec6c335937029cb3569ce7ef81182804d0a", + "reference": "7e4edec6c335937029cb3569ce7ef81182804d0a", "shasum": "" }, "require": { - "php": ">=8.1", - "revolt/event-loop": "^1 || ^0.2" + "php": ">=7.2", + "symfony/css-selector": "^4.4 || ^5.0 || ^6.0 || ^7.0" }, "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "phpunit/phpunit": "^9", - "psalm/phar": "5.23.1" + "phpstan/phpstan": "^1.10", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^8.5.22 || ^9.5.11", + "symfony/error-handler": "^4.4 || ^5.0 || ^6.0 || ^7.0", + "symfony/phpunit-bridge": "^5.4 || ^6.0 || ^7.0" + }, + "suggest": { + "behat/mink-browserkit-driver": "fast headless driver for any app without JS emulation", + "behat/mink-selenium2-driver": "slow, but JS-enabled driver for any app (requires Selenium2)", + "behat/mink-zombie-driver": "fast and JS-enabled headless driver for any app (requires node.js)", + "dmore/chrome-mink-driver": "fast and JS-enabled driver for any app (requires chromium or google chrome)" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, "autoload": { - "files": [ - "src/functions.php", - "src/Future/functions.php", - "src/Internal/functions.php" - ], "psr-4": { - "Amp\\": "src" + "Behat\\Mink\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -47,153 +55,103 @@ ], "authors": [ { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Bob Weinand", - "email": "bobwei9@hotmail.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - }, - { - "name": "Daniel Lowrey", - "email": "rdlowrey@php.net" + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" } ], - "description": "A non-blocking concurrency framework for PHP applications.", - "homepage": "https://amphp.org/amp", + "description": "Browser controller/emulator abstraction for PHP", + "homepage": "https://mink.behat.org/", "keywords": [ - "async", - "asynchronous", - "awaitable", - "concurrency", - "event", - "event-loop", - "future", - "non-blocking", - "promise" + "browser", + "testing", + "web" ], "support": { - "issues": "https://github.com/amphp/amp/issues", - "source": "https://github.com/amphp/amp/tree/v3.1.1" + "issues": "https://github.com/minkphp/Mink/issues", + "source": "https://github.com/minkphp/Mink/tree/v1.12.0" }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2025-08-27T21:42:00+00:00" + "time": "2024-10-30T18:48:14+00:00" }, { - "name": "amphp/byte-stream", - "version": "v2.1.2", + "name": "dbrekelmans/bdi", + "version": "1.4.0", "source": { "type": "git", - "url": "https://github.com/amphp/byte-stream.git", - "reference": "55a6bd071aec26fa2a3e002618c20c35e3df1b46" + "url": "https://github.com/dbrekelmans/bdi.git", + "reference": "fa2ff9b5ed0508ddf5cd574f9dfa6fea954a9acd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/byte-stream/zipball/55a6bd071aec26fa2a3e002618c20c35e3df1b46", - "reference": "55a6bd071aec26fa2a3e002618c20c35e3df1b46", + "url": "https://api.github.com/repos/dbrekelmans/bdi/zipball/fa2ff9b5ed0508ddf5cd574f9dfa6fea954a9acd", + "reference": "fa2ff9b5ed0508ddf5cd574f9dfa6fea954a9acd", "shasum": "" }, "require": { - "amphp/amp": "^3", - "amphp/parser": "^1.1", - "amphp/pipeline": "^1", - "amphp/serialization": "^1", - "amphp/sync": "^2", - "php": ">=8.1", - "revolt/event-loop": "^1 || ^0.2.3" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "amphp/phpunit-util": "^3", - "phpunit/phpunit": "^9", - "psalm/phar": "5.22.1" + "ext-json": "*", + "ext-zip": "*", + "ext-zlib": "*", + "php": "^8.1" }, + "bin": [ + "bdi", + "bdi.phar" + ], "type": "library", - "autoload": { - "files": [ - "src/functions.php", - "src/Internal/functions.php" - ], - "psr-4": { - "Amp\\ByteStream\\": "src" - } - }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" + "name": "Daniël Brekelmans", + "homepage": "https://github.com/dbrekelmans" }, { - "name": "Niklas Keller", - "email": "me@kelunik.com" + "name": "Contributors", + "homepage": "https://github.com/dbrekelmans/bdi/graphs/contributors" } ], - "description": "A stream abstraction to make working with non-blocking I/O simple.", - "homepage": "https://amphp.org/byte-stream", + "description": "PHAR distribution of dbrekelmans/browser-driver-installer.", + "homepage": "https://github.com/dbrekelmans/bdi", "keywords": [ - "amp", - "amphp", - "async", - "io", - "non-blocking", - "stream" + "browser-driver-installer" ], "support": { - "issues": "https://github.com/amphp/byte-stream/issues", - "source": "https://github.com/amphp/byte-stream/tree/v2.1.2" + "source": "https://github.com/dbrekelmans/bdi/tree/1.4.0" }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2025-03-16T17:10:27+00:00" + "time": "2024-12-12T18:36:47+00:00" }, { - "name": "amphp/cache", - "version": "v2.0.1", + "name": "masterminds/html5", + "version": "2.10.0", "source": { "type": "git", - "url": "https://github.com/amphp/cache.git", - "reference": "46912e387e6aa94933b61ea1ead9cf7540b7797c" + "url": "https://github.com/Masterminds/html5-php.git", + "reference": "fcf91eb64359852f00d921887b219479b4f21251" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/cache/zipball/46912e387e6aa94933b61ea1ead9cf7540b7797c", - "reference": "46912e387e6aa94933b61ea1ead9cf7540b7797c", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251", + "reference": "fcf91eb64359852f00d921887b219479b4f21251", "shasum": "" }, "require": { - "amphp/amp": "^3", - "amphp/serialization": "^1", - "amphp/sync": "^2", - "php": ">=8.1", - "revolt/event-loop": "^1 || ^0.2" + "ext-dom": "*", + "php": ">=5.3.0" }, "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "amphp/phpunit-util": "^3", - "phpunit/phpunit": "^9", - "psalm/phar": "^5.4" + "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, "autoload": { "psr-4": { - "Amp\\Cache\\": "src" + "Masterminds\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -202,991 +160,855 @@ ], "authors": [ { - "name": "Niklas Keller", - "email": "me@kelunik.com" + "name": "Matt Butcher", + "email": "technosophos@gmail.com" }, { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" + "name": "Matt Farina", + "email": "matt@mattfarina.com" }, { - "name": "Daniel Lowrey", - "email": "rdlowrey@php.net" + "name": "Asmir Mustafic", + "email": "goetas@gmail.com" } ], - "description": "A fiber-aware cache API based on Amp and Revolt.", - "homepage": "https://amphp.org/cache", + "description": "An HTML5 parser and serializer.", + "homepage": "http://masterminds.github.io/html5-php", + "keywords": [ + "HTML5", + "dom", + "html", + "parser", + "querypath", + "serializer", + "xml" + ], "support": { - "issues": "https://github.com/amphp/cache/issues", - "source": "https://github.com/amphp/cache/tree/v2.0.1" + "issues": "https://github.com/Masterminds/html5-php/issues", + "source": "https://github.com/Masterminds/html5-php/tree/2.10.0" }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2024-04-19T03:38:06+00:00" + "time": "2025-07-25T09:04:22+00:00" }, { - "name": "amphp/dns", - "version": "v2.4.0", + "name": "myclabs/deep-copy", + "version": "1.13.4", "source": { "type": "git", - "url": "https://github.com/amphp/dns.git", - "reference": "78eb3db5fc69bf2fc0cb503c4fcba667bc223c71" + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/dns/zipball/78eb3db5fc69bf2fc0cb503c4fcba667bc223c71", - "reference": "78eb3db5fc69bf2fc0cb503c4fcba667bc223c71", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", "shasum": "" }, "require": { - "amphp/amp": "^3", - "amphp/byte-stream": "^2", - "amphp/cache": "^2", - "amphp/parser": "^1", - "amphp/process": "^2", - "daverandom/libdns": "^2.0.2", - "ext-filter": "*", - "ext-json": "*", - "php": ">=8.1", - "revolt/event-loop": "^1 || ^0.2" + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" }, "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "amphp/phpunit-util": "^3", - "phpunit/phpunit": "^9", - "psalm/phar": "5.20" + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", "autoload": { "files": [ - "src/functions.php" + "src/DeepCopy/deep_copy.php" ], "psr-4": { - "Amp\\Dns\\": "src" + "DeepCopy\\": "src/DeepCopy/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Chris Wright", - "email": "addr@daverandom.com" - }, - { - "name": "Daniel Lowrey", - "email": "rdlowrey@php.net" - }, - { - "name": "Bob Weinand", - "email": "bobwei9@hotmail.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - }, - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - } - ], - "description": "Async DNS resolution for Amp.", - "homepage": "https://github.com/amphp/dns", + "description": "Create deep copies (clones) of your objects", "keywords": [ - "amp", - "amphp", - "async", - "client", - "dns", - "resolve" + "clone", + "copy", + "duplicate", + "object", + "object graph" ], "support": { - "issues": "https://github.com/amphp/dns/issues", - "source": "https://github.com/amphp/dns/tree/v2.4.0" + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" }, "funding": [ { - "url": "https://github.com/amphp", - "type": "github" + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" } ], - "time": "2025-01-19T15:43:40+00:00" + "time": "2025-08-01T08:46:24+00:00" }, { - "name": "amphp/hpack", - "version": "v3.2.1", + "name": "nikic/php-parser", + "version": "v5.6.2", "source": { "type": "git", - "url": "https://github.com/amphp/hpack.git", - "reference": "4f293064b15682a2b178b1367ddf0b8b5feb0239" + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "3a454ca033b9e06b63282ce19562e892747449bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/hpack/zipball/4f293064b15682a2b178b1367ddf0b8b5feb0239", - "reference": "4f293064b15682a2b178b1367ddf0b8b5feb0239", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb", + "reference": "3a454ca033b9e06b63282ce19562e892747449bb", "shasum": "" }, "require": { - "php": ">=7.1" + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" }, "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "http2jp/hpack-test-case": "^1", - "nikic/php-fuzzer": "^0.0.10", - "phpunit/phpunit": "^7 | ^8 | ^9" + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" }, + "bin": [ + "bin/php-parse" + ], "type": "library", "extra": { "branch-alias": { - "dev-master": "3.x-dev" + "dev-master": "5.x-dev" } }, "autoload": { "psr-4": { - "Amp\\Http\\": "src" + "PhpParser\\": "lib/PhpParser" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Daniel Lowrey", - "email": "rdlowrey@php.net" - }, - { - "name": "Bob Weinand" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - }, - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" + "name": "Nikita Popov" } ], - "description": "HTTP/2 HPack implementation.", - "homepage": "https://github.com/amphp/hpack", + "description": "A PHP parser written in PHP", "keywords": [ - "headers", - "hpack", - "http-2" + "parser", + "php" ], "support": { - "issues": "https://github.com/amphp/hpack/issues", - "source": "https://github.com/amphp/hpack/tree/v3.2.1" + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2" }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2024-03-21T19:00:16+00:00" + "time": "2025-10-21T19:32:17+00:00" }, { - "name": "amphp/http", - "version": "v2.1.2", + "name": "phar-io/manifest", + "version": "2.0.4", "source": { "type": "git", - "url": "https://github.com/amphp/http.git", - "reference": "3680d80bd38b5d6f3c2cef2214ca6dd6cef26588" + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/http/zipball/3680d80bd38b5d6f3c2cef2214ca6dd6cef26588", - "reference": "3680d80bd38b5d6f3c2cef2214ca6dd6cef26588", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", "shasum": "" }, "require": { - "amphp/hpack": "^3", - "amphp/parser": "^1.1", - "league/uri-components": "^2.4.2 | ^7.1", - "php": ">=8.1", - "psr/http-message": "^1 | ^2" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "league/uri": "^6.8 | ^7.1", - "phpunit/phpunit": "^9", - "psalm/phar": "^5.26.1" + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" }, "type": "library", - "autoload": { - "files": [ - "src/functions.php", - "src/Internal/constants.php" - ], - "psr-4": { - "Amp\\Http\\": "src" + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Niklas Keller", - "email": "me@kelunik.com" + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" }, { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" } ], - "description": "Basic HTTP primitives which can be shared by servers and clients.", + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { - "issues": "https://github.com/amphp/http/issues", - "source": "https://github.com/amphp/http/tree/v2.1.2" + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" }, "funding": [ { - "url": "https://github.com/amphp", + "url": "https://github.com/theseer", "type": "github" } ], - "time": "2024-11-23T14:57:26+00:00" + "time": "2024-03-03T12:33:53+00:00" }, { - "name": "amphp/http-client", - "version": "v5.3.4", + "name": "phar-io/version", + "version": "3.2.1", "source": { "type": "git", - "url": "https://github.com/amphp/http-client.git", - "reference": "75ad21574fd632594a2dd914496647816d5106bc" + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/http-client/zipball/75ad21574fd632594a2dd914496647816d5106bc", - "reference": "75ad21574fd632594a2dd914496647816d5106bc", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", "shasum": "" }, "require": { - "amphp/amp": "^3", - "amphp/byte-stream": "^2", - "amphp/hpack": "^3", - "amphp/http": "^2", - "amphp/pipeline": "^1", - "amphp/socket": "^2", - "amphp/sync": "^2", - "league/uri": "^7", - "league/uri-components": "^7", - "league/uri-interfaces": "^7.1", - "php": ">=8.1", - "psr/http-message": "^1 | ^2", - "revolt/event-loop": "^1" - }, - "conflict": { - "amphp/file": "<3 | >=5" - }, - "require-dev": { - "amphp/file": "^3 | ^4", - "amphp/http-server": "^3", - "amphp/php-cs-fixer-config": "^2", - "amphp/phpunit-util": "^3", - "ext-json": "*", - "kelunik/link-header-rfc5988": "^1", - "laminas/laminas-diactoros": "^2.3", - "phpunit/phpunit": "^9", - "psalm/phar": "~5.23" - }, - "suggest": { - "amphp/file": "Required for file request bodies and HTTP archive logging", - "ext-json": "Required for logging HTTP archives", - "ext-zlib": "Allows using compression for response bodies." + "php": "^7.2 || ^8.0" }, "type": "library", "autoload": { - "files": [ - "src/functions.php", - "src/Internal/functions.php" - ], - "psr-4": { - "Amp\\Http\\Client\\": "src" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Daniel Lowrey", - "email": "rdlowrey@gmail.com" + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" }, { - "name": "Niklas Keller", - "email": "me@kelunik.com" + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" }, { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" } ], - "description": "An advanced async HTTP client library for PHP, enabling efficient, non-blocking, and concurrent requests and responses.", - "homepage": "https://amphp.org/http-client", - "keywords": [ - "async", - "client", - "concurrent", - "http", - "non-blocking", - "rest" - ], + "description": "Library for handling version information and constraints", "support": { - "issues": "https://github.com/amphp/http-client/issues", - "source": "https://github.com/amphp/http-client/tree/v5.3.4" + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2025-08-16T20:41:23+00:00" + "time": "2022-02-21T01:04:05+00:00" }, { - "name": "amphp/http-server", - "version": "v3.4.3", + "name": "php-webdriver/webdriver", + "version": "1.15.2", "source": { "type": "git", - "url": "https://github.com/amphp/http-server.git", - "reference": "7aa962b0569f664af3ba23bc819f2a69884329cd" + "url": "https://github.com/php-webdriver/php-webdriver.git", + "reference": "998e499b786805568deaf8cbf06f4044f05d91bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/http-server/zipball/7aa962b0569f664af3ba23bc819f2a69884329cd", - "reference": "7aa962b0569f664af3ba23bc819f2a69884329cd", + "url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/998e499b786805568deaf8cbf06f4044f05d91bf", + "reference": "998e499b786805568deaf8cbf06f4044f05d91bf", "shasum": "" }, "require": { - "amphp/amp": "^3", - "amphp/byte-stream": "^2", - "amphp/cache": "^2", - "amphp/hpack": "^3", - "amphp/http": "^2", - "amphp/pipeline": "^1", - "amphp/socket": "^2.1", - "amphp/sync": "^2.2", - "league/uri": "^7.1", - "league/uri-interfaces": "^7.1", - "php": ">=8.1", - "psr/http-message": "^1 | ^2", - "psr/log": "^1 | ^2 | ^3", - "revolt/event-loop": "^1" + "ext-curl": "*", + "ext-json": "*", + "ext-zip": "*", + "php": "^7.3 || ^8.0", + "symfony/polyfill-mbstring": "^1.12", + "symfony/process": "^5.0 || ^6.0 || ^7.0" + }, + "replace": { + "facebook/webdriver": "*" }, "require-dev": { - "amphp/http-client": "^5", - "amphp/log": "^2", - "amphp/php-cs-fixer-config": "^2", - "amphp/phpunit-util": "^3", - "league/uri-components": "^7.1", - "monolog/monolog": "^3", - "phpunit/phpunit": "^9", - "psalm/phar": "~5.23" + "ergebnis/composer-normalize": "^2.20.0", + "ondram/ci-detector": "^4.0", + "php-coveralls/php-coveralls": "^2.4", + "php-mock/php-mock-phpunit": "^2.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpunit/phpunit": "^9.3", + "squizlabs/php_codesniffer": "^3.5", + "symfony/var-dumper": "^5.0 || ^6.0 || ^7.0" }, "suggest": { - "ext-zlib": "Allows GZip compression of response bodies" + "ext-SimpleXML": "For Firefox profile creation" }, "type": "library", "autoload": { "files": [ - "src/Driver/functions.php", - "src/Middleware/functions.php", - "src/functions.php" + "lib/Exception/TimeoutException.php" ], "psr-4": { - "Amp\\Http\\Server\\": "src" + "Facebook\\WebDriver\\": "lib/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Daniel Lowrey", - "email": "rdlowrey@php.net" - }, - { - "name": "Bob Weinand" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - }, - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - } - ], - "description": "A non-blocking HTTP application server for PHP based on Amp.", - "homepage": "https://github.com/amphp/http-server", + "description": "A PHP client for Selenium WebDriver. Previously facebook/webdriver.", + "homepage": "https://github.com/php-webdriver/php-webdriver", "keywords": [ - "amp", - "amphp", - "async", - "http", - "non-blocking", - "server" + "Chromedriver", + "geckodriver", + "php", + "selenium", + "webdriver" ], "support": { - "issues": "https://github.com/amphp/http-server/issues", - "source": "https://github.com/amphp/http-server/tree/v3.4.3" + "issues": "https://github.com/php-webdriver/php-webdriver/issues", + "source": "https://github.com/php-webdriver/php-webdriver/tree/1.15.2" }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2025-05-18T15:43:42+00:00" + "time": "2024-11-21T15:12:59+00:00" }, { - "name": "amphp/parser", - "version": "v1.1.1", - "source": { - "type": "git", - "url": "https://github.com/amphp/parser.git", - "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7" - }, + "name": "phpstan/phpstan", + "version": "1.12.32", "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/parser/zipball/3cf1f8b32a0171d4b1bed93d25617637a77cded7", - "reference": "3cf1f8b32a0171d4b1bed93d25617637a77cded7", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/2770dcdf5078d0b0d53f94317e06affe88419aa8", + "reference": "2770dcdf5078d0b0d53f94317e06affe88419aa8", "shasum": "" }, "require": { - "php": ">=7.4" + "php": "^7.2|^8.0" }, - "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "phpunit/phpunit": "^9", - "psalm/phar": "^5.4" + "conflict": { + "phpstan/phpstan-shim": "*" }, + "bin": [ + "phpstan", + "phpstan.phar" + ], "type": "library", "autoload": { - "psr-4": { - "Amp\\Parser\\": "src" - } + "files": [ + "bootstrap.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - } - ], - "description": "A generator parser to make streaming parsers simple.", - "homepage": "https://github.com/amphp/parser", + "description": "PHPStan - PHP Static Analysis Tool", "keywords": [ - "async", - "non-blocking", - "parser", - "stream" + "dev", + "static analysis" ], "support": { - "issues": "https://github.com/amphp/parser/issues", - "source": "https://github.com/amphp/parser/tree/v1.1.1" + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" }, "funding": [ { - "url": "https://github.com/amphp", + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", "type": "github" } ], - "time": "2024-03-21T19:16:53+00:00" + "time": "2025-09-30T10:16:31+00:00" }, { - "name": "amphp/pipeline", - "version": "v1.2.3", + "name": "phpunit/php-code-coverage", + "version": "12.4.0", "source": { "type": "git", - "url": "https://github.com/amphp/pipeline.git", - "reference": "7b52598c2e9105ebcddf247fc523161581930367" + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "67e8aed88f93d0e6e1cb7effe1a2dfc2fee6022c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/pipeline/zipball/7b52598c2e9105ebcddf247fc523161581930367", - "reference": "7b52598c2e9105ebcddf247fc523161581930367", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/67e8aed88f93d0e6e1cb7effe1a2dfc2fee6022c", + "reference": "67e8aed88f93d0e6e1cb7effe1a2dfc2fee6022c", "shasum": "" }, "require": { - "amphp/amp": "^3", - "php": ">=8.1", - "revolt/event-loop": "^1" + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.6.1", + "php": ">=8.3", + "phpunit/php-file-iterator": "^6.0", + "phpunit/php-text-template": "^5.0", + "sebastian/complexity": "^5.0", + "sebastian/environment": "^8.0.3", + "sebastian/lines-of-code": "^4.0", + "sebastian/version": "^6.0", + "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "amphp/phpunit-util": "^3", - "phpunit/phpunit": "^9", - "psalm/phar": "^5.18" + "phpunit/phpunit": "^12.3.7" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "type": "library", - "autoload": { - "psr-4": { - "Amp\\Pipeline\\": "src" + "extra": { + "branch-alias": { + "dev-main": "12.4.x-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Asynchronous iterators and operators.", - "homepage": "https://amphp.org/pipeline", + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", "keywords": [ - "amp", - "amphp", - "async", - "io", - "iterator", - "non-blocking" + "coverage", + "testing", + "xunit" ], "support": { - "issues": "https://github.com/amphp/pipeline/issues", - "source": "https://github.com/amphp/pipeline/tree/v1.2.3" + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.4.0" }, "funding": [ { - "url": "https://github.com/amphp", + "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage", + "type": "tidelift" } ], - "time": "2025-03-16T16:33:53+00:00" + "time": "2025-09-24T13:44:41+00:00" }, { - "name": "amphp/process", - "version": "v2.0.3", + "name": "phpunit/php-file-iterator", + "version": "6.0.0", "source": { "type": "git", - "url": "https://github.com/amphp/process.git", - "reference": "52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d" + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "961bc913d42fe24a257bfff826a5068079ac7782" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/process/zipball/52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d", - "reference": "52e08c09dec7511d5fbc1fb00d3e4e79fc77d58d", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/961bc913d42fe24a257bfff826a5068079ac7782", + "reference": "961bc913d42fe24a257bfff826a5068079ac7782", "shasum": "" }, "require": { - "amphp/amp": "^3", - "amphp/byte-stream": "^2", - "amphp/sync": "^2", - "php": ">=8.1", - "revolt/event-loop": "^1 || ^0.2" + "php": ">=8.3" }, "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "amphp/phpunit-util": "^3", - "phpunit/phpunit": "^9", - "psalm/phar": "^5.4" + "phpunit/phpunit": "^12.0" }, "type": "library", - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-4": { - "Amp\\Process\\": "src" + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Bob Weinand", - "email": "bobwei9@hotmail.com" - }, - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "A fiber-aware process manager based on Amp and Revolt.", - "homepage": "https://amphp.org/process", + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], "support": { - "issues": "https://github.com/amphp/process/issues", - "source": "https://github.com/amphp/process/tree/v2.0.3" + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/6.0.0" }, "funding": [ { - "url": "https://github.com/amphp", + "url": "https://github.com/sebastianbergmann", "type": "github" } ], - "time": "2024-04-19T03:13:44+00:00" + "time": "2025-02-07T04:58:37+00:00" }, { - "name": "amphp/serialization", - "version": "v1.0.0", + "name": "phpunit/php-invoker", + "version": "6.0.0", "source": { "type": "git", - "url": "https://github.com/amphp/serialization.git", - "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1" + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/serialization/zipball/693e77b2fb0b266c3c7d622317f881de44ae94a1", - "reference": "693e77b2fb0b266c3c7d622317f881de44ae94a1", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/12b54e689b07a25a9b41e57736dfab6ec9ae5406", + "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=8.3" }, "require-dev": { - "amphp/php-cs-fixer-config": "dev-master", - "phpunit/phpunit": "^9 || ^8 || ^7" + "ext-pcntl": "*", + "phpunit/phpunit": "^12.0" + }, + "suggest": { + "ext-pcntl": "*" }, "type": "library", - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-4": { - "Amp\\Serialization\\": "src" + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Serialization tools for IPC and data storage in PHP.", - "homepage": "https://github.com/amphp/serialization", + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", "keywords": [ - "async", - "asynchronous", - "serialization", - "serialize" + "process" ], "support": { - "issues": "https://github.com/amphp/serialization/issues", - "source": "https://github.com/amphp/serialization/tree/master" + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/6.0.0" }, - "time": "2020-03-25T21:39:07+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:58:58+00:00" }, { - "name": "amphp/socket", - "version": "v2.3.1", + "name": "phpunit/php-text-template", + "version": "5.0.0", "source": { "type": "git", - "url": "https://github.com/amphp/socket.git", - "reference": "58e0422221825b79681b72c50c47a930be7bf1e1" + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/socket/zipball/58e0422221825b79681b72c50c47a930be7bf1e1", - "reference": "58e0422221825b79681b72c50c47a930be7bf1e1", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/e1367a453f0eda562eedb4f659e13aa900d66c53", + "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53", "shasum": "" }, "require": { - "amphp/amp": "^3", - "amphp/byte-stream": "^2", - "amphp/dns": "^2", - "ext-openssl": "*", - "kelunik/certificate": "^1.1", - "league/uri": "^6.5 | ^7", - "league/uri-interfaces": "^2.3 | ^7", - "php": ">=8.1", - "revolt/event-loop": "^1 || ^0.2" + "php": ">=8.3" }, "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "amphp/phpunit-util": "^3", - "amphp/process": "^2", - "phpunit/phpunit": "^9", - "psalm/phar": "5.20" + "phpunit/phpunit": "^12.0" }, "type": "library", - "autoload": { - "files": [ - "src/functions.php", - "src/Internal/functions.php", - "src/SocketAddress/functions.php" - ], - "psr-4": { - "Amp\\Socket\\": "src" + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Daniel Lowrey", - "email": "rdlowrey@gmail.com" - }, - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Non-blocking socket connection / server implementations based on Amp and Revolt.", - "homepage": "https://github.com/amphp/socket", + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", "keywords": [ - "amp", - "async", - "encryption", - "non-blocking", - "sockets", - "tcp", - "tls" + "template" ], "support": { - "issues": "https://github.com/amphp/socket/issues", - "source": "https://github.com/amphp/socket/tree/v2.3.1" + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/5.0.0" }, "funding": [ { - "url": "https://github.com/amphp", + "url": "https://github.com/sebastianbergmann", "type": "github" } ], - "time": "2024-04-21T14:33:03+00:00" + "time": "2025-02-07T04:59:16+00:00" }, { - "name": "amphp/sync", - "version": "v2.3.0", + "name": "phpunit/php-timer", + "version": "8.0.0", "source": { "type": "git", - "url": "https://github.com/amphp/sync.git", - "reference": "217097b785130d77cfcc58ff583cf26cd1770bf1" + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/sync/zipball/217097b785130d77cfcc58ff583cf26cd1770bf1", - "reference": "217097b785130d77cfcc58ff583cf26cd1770bf1", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", + "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", "shasum": "" }, "require": { - "amphp/amp": "^3", - "amphp/pipeline": "^1", - "amphp/serialization": "^1", - "php": ">=8.1", - "revolt/event-loop": "^1 || ^0.2" + "php": ">=8.3" }, "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "amphp/phpunit-util": "^3", - "phpunit/phpunit": "^9", - "psalm/phar": "5.23" + "phpunit/phpunit": "^12.0" }, "type": "library", - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-4": { - "Amp\\Sync\\": "src" + "extra": { + "branch-alias": { + "dev-main": "8.0-dev" } }, + "autoload": { + "classmap": [ + "src/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - }, - { - "name": "Stephen Coakley", - "email": "me@stephencoakley.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Non-blocking synchronization primitives for PHP based on Amp and Revolt.", - "homepage": "https://github.com/amphp/sync", + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", "keywords": [ - "async", - "asynchronous", - "mutex", - "semaphore", - "synchronization" + "timer" ], "support": { - "issues": "https://github.com/amphp/sync/issues", - "source": "https://github.com/amphp/sync/tree/v2.3.0" + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/8.0.0" }, "funding": [ { - "url": "https://github.com/amphp", + "url": "https://github.com/sebastianbergmann", "type": "github" } ], - "time": "2024-08-03T19:31:26+00:00" + "time": "2025-02-07T04:59:38+00:00" }, { - "name": "amphp/websocket", - "version": "v2.0.4", + "name": "phpunit/phpunit", + "version": "12.4.0", "source": { "type": "git", - "url": "https://github.com/amphp/websocket.git", - "reference": "963904b6a883c4b62d9222d1d9749814fac96a3b" + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "f62aab5794e36ccd26860db2d1bbf89ac19028d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/websocket/zipball/963904b6a883c4b62d9222d1d9749814fac96a3b", - "reference": "963904b6a883c4b62d9222d1d9749814fac96a3b", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f62aab5794e36ccd26860db2d1bbf89ac19028d9", + "reference": "f62aab5794e36ccd26860db2d1bbf89ac19028d9", "shasum": "" }, "require": { - "amphp/amp": "^3", - "amphp/byte-stream": "^2", - "amphp/parser": "^1", - "amphp/pipeline": "^1", - "amphp/socket": "^2", - "php": ">=8.1", - "revolt/event-loop": "^1" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "amphp/phpunit-util": "^3", - "phpunit/phpunit": "^9", - "psalm/phar": "^5.18" - }, - "suggest": { - "ext-zlib": "Required for compression" + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.4", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=8.3", + "phpunit/php-code-coverage": "^12.4.0", + "phpunit/php-file-iterator": "^6.0.0", + "phpunit/php-invoker": "^6.0.0", + "phpunit/php-text-template": "^5.0.0", + "phpunit/php-timer": "^8.0.0", + "sebastian/cli-parser": "^4.2.0", + "sebastian/comparator": "^7.1.3", + "sebastian/diff": "^7.0.0", + "sebastian/environment": "^8.0.3", + "sebastian/exporter": "^7.0.2", + "sebastian/global-state": "^8.0.2", + "sebastian/object-enumerator": "^7.0.0", + "sebastian/type": "^6.0.3", + "sebastian/version": "^6.0.0", + "staabm/side-effects-detector": "^1.0.5" }, + "bin": [ + "phpunit" + ], "type": "library", + "extra": { + "branch-alias": { + "dev-main": "12.4-dev" + } + }, "autoload": { "files": [ - "src/functions.php" + "src/Framework/Assert/Functions.php" ], - "psr-4": { - "Amp\\Websocket\\": "src" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - }, - { - "name": "Bob Weinand", - "email": "bobwei9@hotmail.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Shared code for websocket servers and clients.", - "homepage": "https://github.com/amphp/websocket", + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", "keywords": [ - "amp", - "amphp", - "async", - "http", - "non-blocking", - "websocket" + "phpunit", + "testing", + "xunit" ], "support": { - "issues": "https://github.com/amphp/websocket/issues", - "source": "https://github.com/amphp/websocket/tree/v2.0.4" + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/12.4.0" }, "funding": [ { - "url": "https://github.com/amphp", + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" } ], - "time": "2024-10-28T21:28:45+00:00" + "time": "2025-10-03T04:28:03+00:00" }, { - "name": "amphp/websocket-client", - "version": "v2.0.2", + "name": "psr/cache", + "version": "3.0.0", "source": { "type": "git", - "url": "https://github.com/amphp/websocket-client.git", - "reference": "dc033fdce0af56295a23f63ac4f579b34d470d6c" + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/websocket-client/zipball/dc033fdce0af56295a23f63ac4f579b34d470d6c", - "reference": "dc033fdce0af56295a23f63ac4f579b34d470d6c", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", "shasum": "" }, "require": { - "amphp/amp": "^3", - "amphp/byte-stream": "^2.1", - "amphp/http": "^2.1", - "amphp/http-client": "^5", - "amphp/socket": "^2.2", - "amphp/websocket": "^2", - "league/uri": "^7.1", - "php": ">=8.1", - "psr/http-message": "^1|^2", - "revolt/event-loop": "^1" - }, - "require-dev": { - "amphp/http-server": "^3", - "amphp/php-cs-fixer-config": "^2", - "amphp/phpunit-util": "^3", - "amphp/websocket-server": "^3|^4", - "phpunit/phpunit": "^9", - "psalm/phar": "~5.26.1", - "psr/log": "^1" + "php": ">=8.0.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { - "files": [ - "src/functions.php" - ], "psr-4": { - "Amp\\Websocket\\Client\\": "src" + "Psr\\Cache\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1195,91 +1017,47 @@ ], "authors": [ { - "name": "Bob Weinand", - "email": "bobwei9@hotmail.com" - }, - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "Async WebSocket client for PHP based on Amp.", + "description": "Common interface for caching libraries", "keywords": [ - "amp", - "amphp", - "async", - "client", - "http", - "non-blocking", - "websocket" + "cache", + "psr", + "psr-6" ], "support": { - "issues": "https://github.com/amphp/websocket-client/issues", - "source": "https://github.com/amphp/websocket-client/tree/v2.0.2" + "source": "https://github.com/php-fig/cache/tree/3.0.0" }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2025-08-24T17:25:34+00:00" + "time": "2021-02-03T23:26:27+00:00" }, { - "name": "brianium/paratest", - "version": "v7.14.1", + "name": "psr/container", + "version": "2.0.2", "source": { "type": "git", - "url": "https://github.com/paratestphp/paratest.git", - "reference": "e1a93c38a94f4808faf75552e835666d3a6f8bb2" + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paratestphp/paratest/zipball/e1a93c38a94f4808faf75552e835666d3a6f8bb2", - "reference": "e1a93c38a94f4808faf75552e835666d3a6f8bb2", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-simplexml": "*", - "fidry/cpu-core-counter": "^1.3.0", - "jean85/pretty-package-versions": "^2.1.1", - "php": "~8.3.0 || ~8.4.0 || ~8.5.0", - "phpunit/php-code-coverage": "^12.4.0", - "phpunit/php-file-iterator": "^6", - "phpunit/php-timer": "^8", - "phpunit/phpunit": "^12.4.0", - "sebastian/environment": "^8.0.3", - "symfony/console": "^6.4.20 || ^7.3.4", - "symfony/process": "^6.4.20 || ^7.3.4" - }, - "require-dev": { - "doctrine/coding-standard": "^14.0.0", - "ext-pcntl": "*", - "ext-pcov": "*", - "ext-posix": "*", - "phpstan/phpstan": "^2.1.30", - "phpstan/phpstan-deprecation-rules": "^2.0.3", - "phpstan/phpstan-phpunit": "^2.0.7", - "phpstan/phpstan-strict-rules": "^2.0.7", - "symfony/filesystem": "^6.4.13 || ^7.3.2" + "php": ">=7.4.0" }, - "bin": [ - "bin/paratest", - "bin/paratest_for_phpstorm" - ], "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, "autoload": { "psr-4": { - "ParaTest\\": [ - "src/" - ] + "Psr\\Container\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1288,735 +1066,669 @@ ], "authors": [ { - "name": "Brian Scaturro", - "email": "scaturrob@gmail.com", - "role": "Developer" - }, - { - "name": "Filippo Tessarotto", - "email": "zoeslam@gmail.com", - "role": "Developer" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "Parallel testing for PHP", - "homepage": "https://github.com/paratestphp/paratest", + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", "keywords": [ - "concurrent", - "parallel", - "phpunit", - "testing" + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" ], "support": { - "issues": "https://github.com/paratestphp/paratest/issues", - "source": "https://github.com/paratestphp/paratest/tree/v7.14.1" + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" }, - "funding": [ - { - "url": "https://github.com/sponsors/Slamdunk", - "type": "github" - }, - { - "url": "https://paypal.me/filippotessarotto", - "type": "paypal" - } - ], - "time": "2025-10-06T08:26:52+00:00" + "time": "2021-11-05T16:47:00+00:00" }, { - "name": "daverandom/libdns", - "version": "v2.1.0", + "name": "psr/event-dispatcher", + "version": "1.0.0", "source": { "type": "git", - "url": "https://github.com/DaveRandom/LibDNS.git", - "reference": "b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a" + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/DaveRandom/LibDNS/zipball/b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a", - "reference": "b84c94e8fe6b7ee4aecfe121bfe3b6177d303c8a", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", "shasum": "" }, "require": { - "ext-ctype": "*", - "php": ">=7.1" - }, - "suggest": { - "ext-intl": "Required for IDN support" + "php": ">=7.2.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { - "files": [ - "src/functions.php" - ], "psr-4": { - "LibDNS\\": "src/" + "Psr\\EventDispatcher\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "DNS protocol implementation written in pure PHP", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", "keywords": [ - "dns" + "events", + "psr", + "psr-14" ], "support": { - "issues": "https://github.com/DaveRandom/LibDNS/issues", - "source": "https://github.com/DaveRandom/LibDNS/tree/v2.1.0" + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" }, - "time": "2024-04-12T12:12:48+00:00" + "time": "2019-01-08T18:20:26+00:00" }, { - "name": "doctrine/deprecations", - "version": "1.1.5", + "name": "psr/log", + "version": "3.0.2", "source": { "type": "git", - "url": "https://github.com/doctrine/deprecations.git", - "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38" + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", - "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" - }, - "conflict": { - "phpunit/phpunit": "<=7.5 || >=13" - }, - "require-dev": { - "doctrine/coding-standard": "^9 || ^12 || ^13", - "phpstan/phpstan": "1.4.10 || 2.1.11", - "phpstan/phpstan-phpunit": "^1.0 || ^2", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12", - "psr/log": "^1 || ^2 || ^3" - }, - "suggest": { - "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + "php": ">=8.0.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, "autoload": { "psr-4": { - "Doctrine\\Deprecations\\": "src" + "Psr\\Log\\": "src" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", - "homepage": "https://www.doctrine-project.org/", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], "support": { - "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.5" + "source": "https://github.com/php-fig/log/tree/3.0.2" }, - "time": "2025-04-07T20:06:18+00:00" + "time": "2024-09-11T13:17:53+00:00" }, { - "name": "fidry/cpu-core-counter", - "version": "1.3.0", + "name": "rector/rector", + "version": "1.2.10", "source": { "type": "git", - "url": "https://github.com/theofidry/cpu-core-counter.git", - "reference": "db9508f7b1474469d9d3c53b86f817e344732678" + "url": "https://github.com/rectorphp/rector.git", + "reference": "40f9cf38c05296bd32f444121336a521a293fa61" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678", - "reference": "db9508f7b1474469d9d3c53b86f817e344732678", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/40f9cf38c05296bd32f444121336a521a293fa61", + "reference": "40f9cf38c05296bd32f444121336a521a293fa61", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": "^7.2|^8.0", + "phpstan/phpstan": "^1.12.5" }, - "require-dev": { - "fidry/makefile": "^0.2.0", - "fidry/php-cs-fixer-config": "^1.1.2", - "phpstan/extension-installer": "^1.2.0", - "phpstan/phpstan": "^2.0", - "phpstan/phpstan-deprecation-rules": "^2.0.0", - "phpstan/phpstan-phpunit": "^2.0", - "phpstan/phpstan-strict-rules": "^2.0", - "phpunit/phpunit": "^8.5.31 || ^9.5.26", - "webmozarts/strict-phpunit": "^7.5" + "conflict": { + "rector/rector-doctrine": "*", + "rector/rector-downgrade-php": "*", + "rector/rector-phpunit": "*", + "rector/rector-symfony": "*" + }, + "suggest": { + "ext-dom": "To manipulate phpunit.xml via the custom-rule command" }, + "bin": [ + "bin/rector" + ], "type": "library", "autoload": { - "psr-4": { - "Fidry\\CpuCoreCounter\\": "src/" - } + "files": [ + "bootstrap.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Théo FIDRY", - "email": "theo.fidry@gmail.com" - } - ], - "description": "Tiny utility to get the number of CPU cores.", + "description": "Instant Upgrade and Automated Refactoring of any PHP code", "keywords": [ - "CPU", - "core" + "automation", + "dev", + "migration", + "refactoring" ], "support": { - "issues": "https://github.com/theofidry/cpu-core-counter/issues", - "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0" + "issues": "https://github.com/rectorphp/rector/issues", + "source": "https://github.com/rectorphp/rector/tree/1.2.10" }, "funding": [ { - "url": "https://github.com/theofidry", + "url": "https://github.com/tomasvotruba", "type": "github" } ], - "time": "2025-08-14T07:29:31+00:00" + "time": "2024-11-08T13:59:10+00:00" }, { - "name": "filp/whoops", - "version": "2.18.4", + "name": "sebastian/cli-parser", + "version": "4.2.0", "source": { "type": "git", - "url": "https://github.com/filp/whoops.git", - "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d" + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "90f41072d220e5c40df6e8635f5dafba2d9d4d04" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/d2102955e48b9fd9ab24280a7ad12ed552752c4d", - "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/90f41072d220e5c40df6e8635f5dafba2d9d4d04", + "reference": "90f41072d220e5c40df6e8635f5dafba2d9d4d04", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0", - "psr/log": "^1.0.1 || ^2.0 || ^3.0" + "php": ">=8.3" }, "require-dev": { - "mockery/mockery": "^1.0", - "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3", - "symfony/var-dumper": "^4.0 || ^5.0" - }, - "suggest": { - "symfony/var-dumper": "Pretty print complex values better with var-dumper available", - "whoops/soap": "Formats errors as SOAP responses" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7-dev" + "dev-main": "4.2-dev" } }, "autoload": { - "psr-4": { - "Whoops\\": "src/Whoops/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Filipe Dobreira", - "homepage": "https://github.com/filp", - "role": "Developer" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "php error handling for cool kids", - "homepage": "https://filp.github.io/whoops/", - "keywords": [ - "error", - "exception", - "handling", - "library", - "throwable", - "whoops" - ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { - "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.18.4" + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/4.2.0" }, "funding": [ { - "url": "https://github.com/denis-sokolov", + "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/cli-parser", + "type": "tidelift" } ], - "time": "2025-08-08T12:00:00+00:00" + "time": "2025-09-14T09:36:45+00:00" }, { - "name": "jean85/pretty-package-versions", - "version": "2.1.1", + "name": "sebastian/comparator", + "version": "7.1.3", "source": { "type": "git", - "url": "https://github.com/Jean85/pretty-package-versions.git", - "reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a" + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "dc904b4bb3ab070865fa4068cd84f3da8b945148" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/4d7aa5dab42e2a76d99559706022885de0e18e1a", - "reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/dc904b4bb3ab070865fa4068cd84f3da8b945148", + "reference": "dc904b4bb3ab070865fa4068cd84f3da8b945148", "shasum": "" }, "require": { - "composer-runtime-api": "^2.1.0", - "php": "^7.4|^8.0" + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.3", + "sebastian/diff": "^7.0", + "sebastian/exporter": "^7.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.2", - "jean85/composer-provided-replaced-stub-package": "^1.0", - "phpstan/phpstan": "^2.0", - "phpunit/phpunit": "^7.5|^8.5|^9.6", - "rector/rector": "^2.0", - "vimeo/psalm": "^4.3 || ^5.0" + "phpunit/phpunit": "^12.2" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-main": "7.1-dev" } }, "autoload": { - "psr-4": { - "Jean85\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Alessandro Lai", - "email": "alessandro.lai85@gmail.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" } ], - "description": "A library to get pretty versions strings of installed dependencies", + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", "keywords": [ - "composer", - "package", - "release", - "versions" + "comparator", + "compare", + "equality" ], "support": { - "issues": "https://github.com/Jean85/pretty-package-versions/issues", - "source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.1" + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/7.1.3" }, - "time": "2025-03-19T14:43:43+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" + } + ], + "time": "2025-08-20T11:27:00+00:00" }, { - "name": "kelunik/certificate", - "version": "v1.1.3", + "name": "sebastian/complexity", + "version": "5.0.0", "source": { "type": "git", - "url": "https://github.com/kelunik/certificate.git", - "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e" + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/kelunik/certificate/zipball/7e00d498c264d5eb4f78c69f41c8bd6719c0199e", - "reference": "7e00d498c264d5eb4f78c69f41c8bd6719c0199e", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/bad4316aba5303d0221f43f8cee37eb58d384bbb", + "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb", "shasum": "" }, "require": { - "ext-openssl": "*", - "php": ">=7.0" + "nikic/php-parser": "^5.0", + "php": ">=8.3" }, "require-dev": { - "amphp/php-cs-fixer-config": "^2", - "phpunit/phpunit": "^6 | 7 | ^8 | ^9" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-main": "5.0-dev" } }, "autoload": { - "psr-4": { - "Kelunik\\Certificate\\": "src" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Niklas Keller", - "email": "me@kelunik.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Access certificate details and transform between different formats.", - "keywords": [ - "DER", - "certificate", - "certificates", - "openssl", - "pem", - "x509" - ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", "support": { - "issues": "https://github.com/kelunik/certificate/issues", - "source": "https://github.com/kelunik/certificate/tree/v1.1.3" + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/5.0.0" }, - "time": "2023-02-03T21:26:53+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:55:25+00:00" }, { - "name": "league/uri", - "version": "7.5.1", + "name": "sebastian/diff", + "version": "7.0.0", "source": { "type": "git", - "url": "https://github.com/thephpleague/uri.git", - "reference": "81fb5145d2644324614cc532b28efd0215bda430" + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "7ab1ea946c012266ca32390913653d844ecd085f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430", - "reference": "81fb5145d2644324614cc532b28efd0215bda430", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f", + "reference": "7ab1ea946c012266ca32390913653d844ecd085f", "shasum": "" }, "require": { - "league/uri-interfaces": "^7.5", - "php": "^8.1" - }, - "conflict": { - "league/uri-schemes": "^1.0" + "php": ">=8.3" }, - "suggest": { - "ext-bcmath": "to improve IPV4 host parsing", - "ext-fileinfo": "to create Data URI from file contennts", - "ext-gmp": "to improve IPV4 host parsing", - "ext-intl": "to handle IDN host with the best performance", - "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", - "league/uri-components": "Needed to easily manipulate URI objects components", - "php-64bit": "to improve IPV4 host parsing", - "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + "require-dev": { + "phpunit/phpunit": "^12.0", + "symfony/process": "^7.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "7.x-dev" + "dev-main": "7.0-dev" } }, "autoload": { - "psr-4": { - "League\\Uri\\": "" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Ignace Nyamagana Butera", - "email": "nyamsprod@gmail.com", - "homepage": "https://nyamsprod.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" } ], - "description": "URI manipulation library", - "homepage": "https://uri.thephpleague.com", + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", "keywords": [ - "data-uri", - "file-uri", - "ftp", - "hostname", - "http", - "https", - "middleware", - "parse_str", - "parse_url", - "psr-7", - "query-string", - "querystring", - "rfc3986", - "rfc3987", - "rfc6570", - "uri", - "uri-template", - "url", - "ws" + "diff", + "udiff", + "unidiff", + "unified diff" ], "support": { - "docs": "https://uri.thephpleague.com", - "forum": "https://thephpleague.slack.com", - "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri/tree/7.5.1" + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/7.0.0" }, "funding": [ { - "url": "https://github.com/sponsors/nyamsprod", + "url": "https://github.com/sebastianbergmann", "type": "github" } ], - "time": "2024-12-08T08:40:02+00:00" + "time": "2025-02-07T04:55:46+00:00" }, { - "name": "league/uri-components", - "version": "7.5.1", + "name": "sebastian/environment", + "version": "8.0.3", "source": { "type": "git", - "url": "https://github.com/thephpleague/uri-components.git", - "reference": "4aabf0e2f2f9421ffcacab35be33e4fb5e63c44f" + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "24a711b5c916efc6d6e62aa65aa2ec98fef77f68" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri-components/zipball/4aabf0e2f2f9421ffcacab35be33e4fb5e63c44f", - "reference": "4aabf0e2f2f9421ffcacab35be33e4fb5e63c44f", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/24a711b5c916efc6d6e62aa65aa2ec98fef77f68", + "reference": "24a711b5c916efc6d6e62aa65aa2ec98fef77f68", "shasum": "" }, "require": { - "league/uri": "^7.5", - "php": "^8.1" + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" }, "suggest": { - "ext-bcmath": "to improve IPV4 host parsing", - "ext-fileinfo": "to create Data URI from file contennts", - "ext-gmp": "to improve IPV4 host parsing", - "ext-intl": "to handle IDN host with the best performance", - "ext-mbstring": "to use the sorting algorithm of URLSearchParams", - "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", - "php-64bit": "to improve IPV4 host parsing", - "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + "ext-posix": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "7.x-dev" + "dev-main": "8.0-dev" } }, "autoload": { - "psr-4": { - "League\\Uri\\": "" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Ignace Nyamagana Butera", - "email": "nyamsprod@gmail.com", - "homepage": "https://nyamsprod.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "URI components manipulation library", - "homepage": "http://uri.thephpleague.com", + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", "keywords": [ - "authority", - "components", - "fragment", - "host", - "middleware", - "modifier", - "path", - "port", - "query", - "rfc3986", - "scheme", - "uri", - "url", - "userinfo" + "Xdebug", + "environment", + "hhvm" ], "support": { - "docs": "https://uri.thephpleague.com", - "forum": "https://thephpleague.slack.com", - "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri-components/tree/7.5.1" + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/8.0.3" }, "funding": [ { - "url": "https://github.com/nyamsprod", + "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/environment", + "type": "tidelift" } ], - "time": "2024-12-08T08:40:02+00:00" + "time": "2025-08-12T14:11:56+00:00" }, { - "name": "league/uri-interfaces", - "version": "7.5.0", + "name": "sebastian/exporter", + "version": "7.0.2", "source": { "type": "git", - "url": "https://github.com/thephpleague/uri-interfaces.git", - "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742" + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "016951ae10980765e4e7aee491eb288c64e505b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", - "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/016951ae10980765e4e7aee491eb288c64e505b7", + "reference": "016951ae10980765e4e7aee491eb288c64e505b7", "shasum": "" }, "require": { - "ext-filter": "*", - "php": "^8.1", - "psr/http-factory": "^1", - "psr/http-message": "^1.1 || ^2.0" + "ext-mbstring": "*", + "php": ">=8.3", + "sebastian/recursion-context": "^7.0" }, - "suggest": { - "ext-bcmath": "to improve IPV4 host parsing", - "ext-gmp": "to improve IPV4 host parsing", - "ext-intl": "to handle IDN host with the best performance", - "php-64bit": "to improve IPV4 host parsing", - "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + "require-dev": { + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "7.x-dev" + "dev-main": "7.0-dev" } }, "autoload": { - "psr-4": { - "League\\Uri\\": "" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Ignace Nyamagana Butera", - "email": "nyamsprod@gmail.com", - "homepage": "https://nyamsprod.com" - } - ], - "description": "Common interfaces and classes for URI representation and interaction", - "homepage": "https://uri.thephpleague.com", - "keywords": [ - "data-uri", - "file-uri", - "ftp", - "hostname", - "http", - "https", - "parse_str", - "parse_url", - "psr-7", - "query-string", - "querystring", - "rfc3986", - "rfc3987", - "rfc6570", - "uri", - "url", - "ws" - ], - "support": { - "docs": "https://uri.thephpleague.com", - "forum": "https://thephpleague.slack.com", - "issues": "https://github.com/thephpleague/uri-src/issues", - "source": "https://github.com/thephpleague/uri-interfaces/tree/7.5.0" - }, - "funding": [ + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, { - "url": "https://github.com/sponsors/nyamsprod", - "type": "github" - } - ], - "time": "2024-12-08T08:18:47+00:00" - }, - { - "name": "myclabs/deep-copy", - "version": "1.13.4", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", - "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "conflict": { - "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3 <3.2.2" - }, - "require-dev": { - "doctrine/collections": "^1.6.8", - "doctrine/common": "^2.13.3 || ^3.2.2", - "phpspec/prophecy": "^1.10", - "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" - }, - "type": "library", - "autoload": { - "files": [ - "src/DeepCopy/deep_copy.php" - ], - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" ], - "description": "Create deep copies (clones) of your objects", + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" + "export", + "exporter" ], "support": { - "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/7.0.2" }, "funding": [ { - "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", "type": "tidelift" } ], - "time": "2025-08-01T08:46:24+00:00" + "time": "2025-09-24T06:16:11+00:00" }, { - "name": "nikic/php-parser", - "version": "v5.6.2", + "name": "sebastian/global-state", + "version": "8.0.2", "source": { "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "3a454ca033b9e06b63282ce19562e892747449bb" + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "ef1377171613d09edd25b7816f05be8313f9115d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb", - "reference": "3a454ca033b9e06b63282ce19562e892747449bb", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/ef1377171613d09edd25b7816f05be8313f9115d", + "reference": "ef1377171613d09edd25b7816f05be8313f9115d", "shasum": "" }, "require": { - "ext-ctype": "*", - "ext-json": "*", - "ext-tokenizer": "*", - "php": ">=7.4" + "php": ">=8.3", + "sebastian/object-reflector": "^5.0", + "sebastian/recursion-context": "^7.0" }, "require-dev": { - "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^9.0" + "ext-dom": "*", + "phpunit/phpunit": "^12.0" }, - "bin": [ - "bin/php-parse" - ], "type": "library", "extra": { "branch-alias": { - "dev-master": "5.x-dev" + "dev-main": "8.0-dev" } }, "autoload": { - "psr-4": { - "PhpParser\\": "lib/PhpParser" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2024,575 +1736,495 @@ ], "authors": [ { - "name": "Nikita Popov" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "A PHP parser written in PHP", + "description": "Snapshotting of global state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", "keywords": [ - "parser", - "php" + "global state" ], "support": { - "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2" + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/8.0.2" }, - "time": "2025-10-21T19:32:17+00:00" + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state", + "type": "tidelift" + } + ], + "time": "2025-08-29T11:29:25+00:00" }, { - "name": "nunomaduro/collision", - "version": "v8.8.2", + "name": "sebastian/lines-of-code", + "version": "4.0.0", "source": { "type": "git", - "url": "https://github.com/nunomaduro/collision.git", - "reference": "60207965f9b7b7a4ce15a0f75d57f9dadb105bdb" + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/60207965f9b7b7a4ce15a0f75d57f9dadb105bdb", - "reference": "60207965f9b7b7a4ce15a0f75d57f9dadb105bdb", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/97ffee3bcfb5805568d6af7f0f893678fc076d2f", + "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f", "shasum": "" }, "require": { - "filp/whoops": "^2.18.1", - "nunomaduro/termwind": "^2.3.1", - "php": "^8.2.0", - "symfony/console": "^7.3.0" - }, - "conflict": { - "laravel/framework": "<11.44.2 || >=13.0.0", - "phpunit/phpunit": "<11.5.15 || >=13.0.0" + "nikic/php-parser": "^5.0", + "php": ">=8.3" }, "require-dev": { - "brianium/paratest": "^7.8.3", - "larastan/larastan": "^3.4.2", - "laravel/framework": "^11.44.2 || ^12.18", - "laravel/pint": "^1.22.1", - "laravel/sail": "^1.43.1", - "laravel/sanctum": "^4.1.1", - "laravel/tinker": "^2.10.1", - "orchestra/testbench-core": "^9.12.0 || ^10.4", - "pestphp/pest": "^3.8.2", - "sebastian/environment": "^7.2.1 || ^8.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { - "laravel": { - "providers": [ - "NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider" - ] - }, "branch-alias": { - "dev-8.x": "8.x-dev" + "dev-main": "4.0-dev" } }, "autoload": { - "files": [ - "./src/Adapters/Phpunit/Autoload.php" - ], - "psr-4": { - "NunoMaduro\\Collision\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Nuno Maduro", - "email": "enunomaduro@gmail.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Cli error handling for console/command-line PHP applications.", - "keywords": [ - "artisan", - "cli", - "command-line", - "console", - "dev", - "error", - "handling", - "laravel", - "laravel-zero", - "php", - "symfony" - ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { - "issues": "https://github.com/nunomaduro/collision/issues", - "source": "https://github.com/nunomaduro/collision" + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/4.0.0" }, "funding": [ { - "url": "https://www.paypal.com/paypalme/enunomaduro", - "type": "custom" - }, - { - "url": "https://github.com/nunomaduro", + "url": "https://github.com/sebastianbergmann", "type": "github" - }, - { - "url": "https://www.patreon.com/nunomaduro", - "type": "patreon" } ], - "time": "2025-06-25T02:12:12+00:00" + "time": "2025-02-07T04:57:28+00:00" }, { - "name": "nunomaduro/termwind", - "version": "v2.3.2", + "name": "sebastian/object-enumerator", + "version": "7.0.0", "source": { "type": "git", - "url": "https://github.com/nunomaduro/termwind.git", - "reference": "eb61920a53057a7debd718a5b89c2178032b52c0" + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/eb61920a53057a7debd718a5b89c2178032b52c0", - "reference": "eb61920a53057a7debd718a5b89c2178032b52c0", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1effe8e9b8e068e9ae228e542d5d11b5d16db894", + "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894", "shasum": "" }, "require": { - "ext-mbstring": "*", - "php": "^8.2", - "symfony/console": "^7.3.4" + "php": ">=8.3", + "sebastian/object-reflector": "^5.0", + "sebastian/recursion-context": "^7.0" }, "require-dev": { - "illuminate/console": "^11.46.1", - "laravel/pint": "^1.25.1", - "mockery/mockery": "^1.6.12", - "pestphp/pest": "^2.36.0 || ^3.8.4", - "phpstan/phpstan": "^1.12.32", - "phpstan/phpstan-strict-rules": "^1.6.2", - "symfony/var-dumper": "^7.3.4", - "thecodingmachine/phpstan-strict-rules": "^1.0.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { - "laravel": { - "providers": [ - "Termwind\\Laravel\\TermwindServiceProvider" - ] - }, "branch-alias": { - "dev-2.x": "2.x-dev" + "dev-main": "7.0-dev" } }, "autoload": { - "files": [ - "src/Functions.php" - ], - "psr-4": { - "Termwind\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Nuno Maduro", - "email": "enunomaduro@gmail.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "Its like Tailwind CSS, but for the console.", - "keywords": [ - "cli", - "console", - "css", - "package", - "php", - "style" - ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "support": { - "issues": "https://github.com/nunomaduro/termwind/issues", - "source": "https://github.com/nunomaduro/termwind/tree/v2.3.2" + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/7.0.0" }, "funding": [ { - "url": "https://www.paypal.com/paypalme/enunomaduro", - "type": "custom" - }, - { - "url": "https://github.com/nunomaduro", - "type": "github" - }, - { - "url": "https://github.com/xiCO2k", + "url": "https://github.com/sebastianbergmann", "type": "github" } ], - "time": "2025-10-18T11:10:27+00:00" + "time": "2025-02-07T04:57:48+00:00" }, { - "name": "pestphp/pest", - "version": "v4.1.2", + "name": "sebastian/object-reflector", + "version": "5.0.0", "source": { "type": "git", - "url": "https://github.com/pestphp/pest.git", - "reference": "08b09f2e98fc6830050c0237968b233768642d46" + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "4bfa827c969c98be1e527abd576533293c634f6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest/zipball/08b09f2e98fc6830050c0237968b233768642d46", - "reference": "08b09f2e98fc6830050c0237968b233768642d46", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/4bfa827c969c98be1e527abd576533293c634f6a", + "reference": "4bfa827c969c98be1e527abd576533293c634f6a", "shasum": "" }, "require": { - "brianium/paratest": "^7.14.0", - "nunomaduro/collision": "^8.8.2", - "nunomaduro/termwind": "^2.3.1", - "pestphp/pest-plugin": "^4.0.0", - "pestphp/pest-plugin-arch": "^4.0.0", - "pestphp/pest-plugin-mutate": "^4.0.1", - "pestphp/pest-plugin-profanity": "^4.1.0", - "php": "^8.3.0", - "phpunit/phpunit": "^12.4.0", - "symfony/process": "^7.3.4" - }, - "conflict": { - "filp/whoops": "<2.18.3", - "phpunit/phpunit": ">12.4.0", - "sebastian/exporter": "<7.0.0", - "webmozart/assert": "<1.11.0" + "php": ">=8.3" }, "require-dev": { - "pestphp/pest-dev-tools": "^4.0.0", - "pestphp/pest-plugin-browser": "^4.1.1", - "pestphp/pest-plugin-type-coverage": "^4.0.2", - "psy/psysh": "^0.12.12" + "phpunit/phpunit": "^12.0" }, - "bin": [ - "bin/pest" - ], "type": "library", "extra": { - "pest": { - "plugins": [ - "Pest\\Mutate\\Plugins\\Mutate", - "Pest\\Plugins\\Configuration", - "Pest\\Plugins\\Bail", - "Pest\\Plugins\\Cache", - "Pest\\Plugins\\Coverage", - "Pest\\Plugins\\Init", - "Pest\\Plugins\\Environment", - "Pest\\Plugins\\Help", - "Pest\\Plugins\\Memory", - "Pest\\Plugins\\Only", - "Pest\\Plugins\\Printer", - "Pest\\Plugins\\ProcessIsolation", - "Pest\\Plugins\\Profile", - "Pest\\Plugins\\Retry", - "Pest\\Plugins\\Snapshot", - "Pest\\Plugins\\Verbose", - "Pest\\Plugins\\Version", - "Pest\\Plugins\\Shard", - "Pest\\Plugins\\Parallel" - ] - }, - "phpstan": { - "includes": [ - "extension.neon" - ] + "branch-alias": { + "dev-main": "5.0-dev" } }, "autoload": { - "files": [ - "src/Functions.php", - "src/Pest.php" - ], - "psr-4": { - "Pest\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Nuno Maduro", - "email": "enunomaduro@gmail.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" } ], - "description": "The elegant PHP Testing Framework.", - "keywords": [ - "framework", - "pest", - "php", - "test", - "testing", - "unit" - ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", "support": { - "issues": "https://github.com/pestphp/pest/issues", - "source": "https://github.com/pestphp/pest/tree/v4.1.2" + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/5.0.0" }, "funding": [ { - "url": "https://www.paypal.com/paypalme/enunomaduro", - "type": "custom" - }, - { - "url": "https://github.com/nunomaduro", + "url": "https://github.com/sebastianbergmann", "type": "github" } ], - "time": "2025-10-05T19:09:49+00:00" + "time": "2025-02-07T04:58:17+00:00" }, { - "name": "pestphp/pest-plugin", - "version": "v4.0.0", + "name": "sebastian/recursion-context", + "version": "7.0.1", "source": { "type": "git", - "url": "https://github.com/pestphp/pest-plugin.git", - "reference": "9d4b93d7f73d3f9c3189bb22c220fef271cdf568" + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest-plugin/zipball/9d4b93d7f73d3f9c3189bb22c220fef271cdf568", - "reference": "9d4b93d7f73d3f9c3189bb22c220fef271cdf568", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/0b01998a7d5b1f122911a66bebcb8d46f0c82d8c", + "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c", "shasum": "" }, "require": { - "composer-plugin-api": "^2.0.0", - "composer-runtime-api": "^2.2.2", - "php": "^8.3" - }, - "conflict": { - "pestphp/pest": "<4.0.0" + "php": ">=8.3" }, "require-dev": { - "composer/composer": "^2.8.10", - "pestphp/pest": "^4.0.0", - "pestphp/pest-dev-tools": "^4.0.0" + "phpunit/phpunit": "^12.0" }, - "type": "composer-plugin", + "type": "library", "extra": { - "class": "Pest\\Plugin\\Manager" + "branch-alias": { + "dev-main": "7.0-dev" + } }, "autoload": { - "psr-4": { - "Pest\\Plugin\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], - "description": "The Pest plugin manager", - "keywords": [ - "framework", - "manager", - "pest", - "php", - "plugin", - "test", - "testing", - "unit" + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { - "source": "https://github.com/pestphp/pest-plugin/tree/v4.0.0" + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/7.0.1" }, "funding": [ { - "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=66BYDWAT92N6L", - "type": "custom" + "url": "https://github.com/sebastianbergmann", + "type": "github" }, { - "url": "https://github.com/nunomaduro", - "type": "github" + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" }, { - "url": "https://www.patreon.com/nunomaduro", - "type": "patreon" + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "type": "tidelift" } ], - "time": "2025-08-20T12:35:58+00:00" + "time": "2025-08-13T04:44:59+00:00" }, { - "name": "pestphp/pest-plugin-arch", - "version": "v4.0.0", + "name": "sebastian/type", + "version": "6.0.3", "source": { "type": "git", - "url": "https://github.com/pestphp/pest-plugin-arch.git", - "reference": "25bb17e37920ccc35cbbcda3b00d596aadf3e58d" + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "e549163b9760b8f71f191651d22acf32d56d6d4d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest-plugin-arch/zipball/25bb17e37920ccc35cbbcda3b00d596aadf3e58d", - "reference": "25bb17e37920ccc35cbbcda3b00d596aadf3e58d", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/e549163b9760b8f71f191651d22acf32d56d6d4d", + "reference": "e549163b9760b8f71f191651d22acf32d56d6d4d", "shasum": "" }, "require": { - "pestphp/pest-plugin": "^4.0.0", - "php": "^8.3", - "ta-tikoma/phpunit-architecture-test": "^0.8.5" + "php": ">=8.3" }, "require-dev": { - "pestphp/pest": "^4.0.0", - "pestphp/pest-dev-tools": "^4.0.0" + "phpunit/phpunit": "^12.0" }, "type": "library", "extra": { - "pest": { - "plugins": [ - "Pest\\Arch\\Plugin" - ] + "branch-alias": { + "dev-main": "6.0-dev" } }, "autoload": { - "files": [ - "src/Autoload.php" - ], - "psr-4": { - "Pest\\Arch\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], - "description": "The Arch plugin for Pest PHP.", - "keywords": [ - "arch", - "architecture", - "framework", - "pest", - "php", - "plugin", - "test", - "testing", - "unit" + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", "support": { - "source": "https://github.com/pestphp/pest-plugin-arch/tree/v4.0.0" + "issues": "https://github.com/sebastianbergmann/type/issues", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/6.0.3" }, "funding": [ { - "url": "https://www.paypal.com/paypalme/enunomaduro", - "type": "custom" + "url": "https://github.com/sebastianbergmann", + "type": "github" }, { - "url": "https://github.com/nunomaduro", - "type": "github" + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/type", + "type": "tidelift" } ], - "time": "2025-08-20T13:10:51+00:00" + "time": "2025-08-09T06:57:12+00:00" }, { - "name": "pestphp/pest-plugin-browser", - "version": "v4.1.1", + "name": "sebastian/version", + "version": "6.0.0", "source": { "type": "git", - "url": "https://github.com/pestphp/pest-plugin-browser.git", - "reference": "da70fce21e4b33ba22bef1276f654e77676213d7" + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest-plugin-browser/zipball/da70fce21e4b33ba22bef1276f654e77676213d7", - "reference": "da70fce21e4b33ba22bef1276f654e77676213d7", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/3e6ccf7657d4f0a59200564b08cead899313b53c", + "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c", "shasum": "" }, "require": { - "amphp/amp": "^3.1.1", - "amphp/http-server": "^3.4.3", - "amphp/websocket-client": "^2.0.2", - "ext-sockets": "*", - "pestphp/pest": "^4.1.0", - "pestphp/pest-plugin": "^4.0.0", - "php": "^8.3", - "symfony/process": "^7.3.4" - }, - "require-dev": { - "ext-pcntl": "*", - "ext-posix": "*", - "livewire/livewire": "^3.6.4", - "nunomaduro/collision": "^8.8.2", - "orchestra/testbench": "^10.6.0", - "pestphp/pest-dev-tools": "^4.0.0", - "pestphp/pest-plugin-laravel": "^4.0", - "pestphp/pest-plugin-type-coverage": "^4.0.2" + "php": ">=8.3" }, "type": "library", "extra": { - "pest": { - "plugins": [ - "Pest\\Browser\\Plugin" - ] + "branch-alias": { + "dev-main": "6.0-dev" } }, "autoload": { - "files": [ - "src/Autoload.php" - ], - "psr-4": { - "Pest\\Browser\\": "src/" + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" } + ], + "time": "2025-02-07T05:00:38+00:00" + }, + { + "name": "staabm/side-effects-detector", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "Pest plugin to test browser interactions", + "description": "A static analysis tool to detect side effects in PHP code", "keywords": [ - "browser", - "framework", - "pest", - "php", - "test", - "testing", - "unit" + "static analysis" ], "support": { - "source": "https://github.com/pestphp/pest-plugin-browser/tree/v4.1.1" + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" }, "funding": [ { - "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=66BYDWAT92N6L", - "type": "custom" - }, - { - "url": "https://github.com/nunomaduro", + "url": "https://github.com/staabm", "type": "github" - }, - { - "url": "https://www.patreon.com/nunomaduro", - "type": "patreon" } ], - "time": "2025-09-29T01:31:33+00:00" + "time": "2024-10-20T05:08:20+00:00" }, { - "name": "pestphp/pest-plugin-mutate", - "version": "v4.0.1", + "name": "symfony/browser-kit", + "version": "v7.3.2", "source": { "type": "git", - "url": "https://github.com/pestphp/pest-plugin-mutate.git", - "reference": "d9b32b60b2385e1688a68cc227594738ec26d96c" + "url": "https://github.com/symfony/browser-kit.git", + "reference": "f0b889b73a845cddef1d25fe207b37fd04cb5419" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest-plugin-mutate/zipball/d9b32b60b2385e1688a68cc227594738ec26d96c", - "reference": "d9b32b60b2385e1688a68cc227594738ec26d96c", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/f0b889b73a845cddef1d25fe207b37fd04cb5419", + "reference": "f0b889b73a845cddef1d25fe207b37fd04cb5419", "shasum": "" }, "require": { - "nikic/php-parser": "^5.6.1", - "pestphp/pest-plugin": "^4.0.0", - "php": "^8.3", - "psr/simple-cache": "^3.0.0" + "php": ">=8.2", + "symfony/dom-crawler": "^6.4|^7.0" }, "require-dev": { - "pestphp/pest": "^4.0.0", - "pestphp/pest-dev-tools": "^4.0.0", - "pestphp/pest-plugin-type-coverage": "^4.0.0" + "symfony/css-selector": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0" }, "type": "library", "autoload": { "psr-4": { - "Pest\\Mutate\\": "src/" - } + "Symfony\\Component\\BrowserKit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2600,245 +2232,172 @@ ], "authors": [ { - "name": "Nuno Maduro", - "email": "enunomaduro@gmail.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { - "name": "Sandro Gehri", - "email": "sandrogehri@gmail.com" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Mutates your code to find untested cases", - "keywords": [ - "framework", - "mutate", - "mutation", - "pest", - "php", - "plugin", - "test", - "testing", - "unit" - ], + "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", + "homepage": "https://symfony.com", "support": { - "source": "https://github.com/pestphp/pest-plugin-mutate/tree/v4.0.1" + "source": "https://github.com/symfony/browser-kit/tree/v7.3.2" }, "funding": [ { - "url": "https://www.paypal.com/paypalme/enunomaduro", + "url": "https://symfony.com/sponsor", "type": "custom" }, { - "url": "https://github.com/gehrisandro", + "url": "https://github.com/fabpot", "type": "github" }, { - "url": "https://github.com/nunomaduro", + "url": "https://github.com/nicolas-grekas", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "time": "2025-08-21T20:19:25+00:00" + "time": "2025-07-10T08:47:49+00:00" }, { - "name": "pestphp/pest-plugin-profanity", - "version": "v4.1.0", + "name": "symfony/cache", + "version": "v7.3.5", "source": { "type": "git", - "url": "https://github.com/pestphp/pest-plugin-profanity.git", - "reference": "e279c844b6868da92052be27b5202c2ad7216e80" + "url": "https://github.com/symfony/cache.git", + "reference": "4a55feb59664f49042a0824c0f955e2f4c1412ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest-plugin-profanity/zipball/e279c844b6868da92052be27b5202c2ad7216e80", - "reference": "e279c844b6868da92052be27b5202c2ad7216e80", + "url": "https://api.github.com/repos/symfony/cache/zipball/4a55feb59664f49042a0824c0f955e2f4c1412ad", + "reference": "4a55feb59664f49042a0824c0f955e2f4c1412ad", "shasum": "" }, "require": { - "pestphp/pest-plugin": "^4.0.0", - "php": "^8.3" + "php": ">=8.2", + "psr/cache": "^2.0|^3.0", + "psr/log": "^1.1|^2|^3", + "symfony/cache-contracts": "^3.6", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/var-exporter": "^6.4|^7.0" + }, + "conflict": { + "doctrine/dbal": "<3.6", + "symfony/dependency-injection": "<6.4", + "symfony/http-kernel": "<6.4", + "symfony/var-dumper": "<6.4" + }, + "provide": { + "psr/cache-implementation": "2.0|3.0", + "psr/simple-cache-implementation": "1.0|2.0|3.0", + "symfony/cache-implementation": "1.1|2.0|3.0" }, "require-dev": { - "faissaloux/pest-plugin-inside": "^1.9", - "pestphp/pest": "^4.0.0", - "pestphp/pest-dev-tools": "^4.0.0" + "cache/integration-tests": "dev-master", + "doctrine/dbal": "^3.6|^4", + "predis/predis": "^1.1|^2.0", + "psr/simple-cache": "^1.0|^2.0|^3.0", + "symfony/clock": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/filesystem": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" }, "type": "library", - "extra": { - "pest": { - "plugins": [ - "Pest\\Profanity\\Plugin" - ] - } - }, "autoload": { "psr-4": { - "Pest\\Profanity\\": "src/" - } + "Symfony\\Component\\Cache\\": "" + }, + "classmap": [ + "Traits/ValueWrapper.php" + ], + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "The Pest Profanity Plugin", - "keywords": [ - "framework", - "pest", - "php", - "plugin", - "profanity", - "test", - "testing", - "unit" - ], - "support": { - "source": "https://github.com/pestphp/pest-plugin-profanity/tree/v4.1.0" - }, - "time": "2025-09-10T06:17:03+00:00" - }, - { - "name": "phar-io/manifest", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "54750ef60c58e43759730615a392c31c80e23176" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", - "reference": "54750ef60c58e43759730615a392c31c80e23176", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-libxml": "*", - "ext-phar": "*", - "ext-xmlwriter": "*", - "phar-io/version": "^3.0.1", - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], "authors": [ { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", + "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], "support": { - "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.4" + "source": "https://github.com/symfony/cache/tree/v7.3.5" }, "funding": [ { - "url": "https://github.com/theseer", - "type": "github" - } - ], - "time": "2024-03-03T12:33:53+00:00" - }, - { - "name": "phar-io/version", - "version": "3.2.1", - "source": { - "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ + "url": "https://symfony.com/sponsor", + "type": "custom" + }, { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" + "url": "https://github.com/fabpot", + "type": "github" }, { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" + "url": "https://github.com/nicolas-grekas", + "type": "github" }, { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "description": "Library for handling version information and constraints", - "support": { - "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.2.1" - }, - "time": "2022-02-21T01:04:05+00:00" + "time": "2025-10-16T13:55:38+00:00" }, { - "name": "phpdocumentor/reflection-common", - "version": "2.2.0", + "name": "symfony/cache-contracts", + "version": "v3.6.0", "source": { "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/5d68a57d66910405e5c0b63d6f0af941e66fc868", + "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": ">=8.1", + "psr/cache": "^3.0" }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { - "dev-2.x": "2.x-dev" + "dev-main": "3.6-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": "src/" + "Symfony\\Contracts\\Cache\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -2847,2076 +2406,1281 @@ ], "authors": [ { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", + "description": "Generic abstractions related to caching", + "homepage": "https://symfony.com", "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" ], "support": { - "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", - "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" - }, - "time": "2020-06-27T09:03:43+00:00" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "5.6.3", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94f8051919d1b0369a6bcc7931d679a511c03fe9", - "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9", - "shasum": "" - }, - "require": { - "doctrine/deprecations": "^1.1", - "ext-filter": "*", - "php": "^7.4 || ^8.0", - "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.7", - "phpstan/phpdoc-parser": "^1.7|^2.0", - "webmozart/assert": "^1.9.1" - }, - "require-dev": { - "mockery/mockery": "~1.3.5 || ~1.6.0", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-mockery": "^1.1", - "phpstan/phpstan-webmozart-assert": "^1.2", - "phpunit/phpunit": "^9.5", - "psalm/phar": "^5.26" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } + "source": "https://github.com/symfony/cache-contracts/tree/v3.6.0" }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ + "funding": [ { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" + "url": "https://symfony.com/sponsor", + "type": "custom" }, { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.3" - }, - "time": "2025-08-01T19:43:32+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "1.10.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a", - "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a", - "shasum": "" - }, - "require": { - "doctrine/deprecations": "^1.0", - "php": "^7.3 || ^8.0", - "phpdocumentor/reflection-common": "^2.0", - "phpstan/phpdoc-parser": "^1.18|^2.0" - }, - "require-dev": { - "ext-tokenizer": "*", - "phpbench/phpbench": "^1.2", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-phpunit": "^1.1", - "phpunit/phpunit": "^9.5", - "rector/rector": "^0.13.9", - "vimeo/psalm": "^4.25" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ + "url": "https://github.com/fabpot", + "type": "github" + }, { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "support": { - "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0" - }, - "time": "2024-11-09T15:12:26+00:00" - }, - { - "name": "phpstan/phpdoc-parser", - "version": "2.3.0", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/1e0cd5370df5dd2e556a36b9c62f62e555870495", - "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495", - "shasum": "" - }, - "require": { - "php": "^7.4 || ^8.0" - }, - "require-dev": { - "doctrine/annotations": "^2.0", - "nikic/php-parser": "^5.3.0", - "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^2.0", - "phpstan/phpstan-phpunit": "^2.0", - "phpstan/phpstan-strict-rules": "^2.0", - "phpunit/phpunit": "^9.6", - "symfony/process": "^5.2" - }, - "type": "library", - "autoload": { - "psr-4": { - "PHPStan\\PhpDocParser\\": [ - "src/" - ] + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPDoc parser with support for nullable, intersection and generic types", - "support": { - "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.0" - }, - "time": "2025-08-30T15:50:23+00:00" - }, - { - "name": "phpstan/phpstan", - "version": "1.12.32", - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/2770dcdf5078d0b0d53f94317e06affe88419aa8", - "reference": "2770dcdf5078d0b0d53f94317e06affe88419aa8", - "shasum": "" - }, - "require": { - "php": "^7.2|^8.0" - }, - "conflict": { - "phpstan/phpstan-shim": "*" - }, - "bin": [ - "phpstan", - "phpstan.phar" - ], - "type": "library", - "autoload": { - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPStan - PHP Static Analysis Tool", - "keywords": [ - "dev", - "static analysis" - ], - "support": { - "docs": "https://phpstan.org/user-guide/getting-started", - "forum": "https://github.com/phpstan/phpstan/discussions", - "issues": "https://github.com/phpstan/phpstan/issues", - "security": "https://github.com/phpstan/phpstan/security/policy", - "source": "https://github.com/phpstan/phpstan-src" - }, - "funding": [ - { - "url": "https://github.com/ondrejmirtes", - "type": "github" - }, - { - "url": "https://github.com/phpstan", - "type": "github" - } - ], - "time": "2025-09-30T10:16:31+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "12.4.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "67e8aed88f93d0e6e1cb7effe1a2dfc2fee6022c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/67e8aed88f93d0e6e1cb7effe1a2dfc2fee6022c", - "reference": "67e8aed88f93d0e6e1cb7effe1a2dfc2fee6022c", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-libxml": "*", - "ext-xmlwriter": "*", - "nikic/php-parser": "^5.6.1", - "php": ">=8.3", - "phpunit/php-file-iterator": "^6.0", - "phpunit/php-text-template": "^5.0", - "sebastian/complexity": "^5.0", - "sebastian/environment": "^8.0.3", - "sebastian/lines-of-code": "^4.0", - "sebastian/version": "^6.0", - "theseer/tokenizer": "^1.2.3" - }, - "require-dev": { - "phpunit/phpunit": "^12.3.7" - }, - "suggest": { - "ext-pcov": "PHP extension that provides line coverage", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "12.4.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.4.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - }, - { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" - }, - { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage", - "type": "tidelift" - } - ], - "time": "2025-09-24T13:44:41+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "6.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "961bc913d42fe24a257bfff826a5068079ac7782" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/961bc913d42fe24a257bfff826a5068079ac7782", - "reference": "961bc913d42fe24a257bfff826a5068079ac7782", - "shasum": "" - }, - "require": { - "php": ">=8.3" - }, - "require-dev": { - "phpunit/phpunit": "^12.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "6.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/6.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2025-02-07T04:58:37+00:00" - }, - { - "name": "phpunit/php-invoker", - "version": "6.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/12b54e689b07a25a9b41e57736dfab6ec9ae5406", - "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406", - "shasum": "" - }, - "require": { - "php": ">=8.3" - }, - "require-dev": { - "ext-pcntl": "*", - "phpunit/phpunit": "^12.0" - }, - "suggest": { - "ext-pcntl": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "6.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Invoke callables with a timeout", - "homepage": "https://github.com/sebastianbergmann/php-invoker/", - "keywords": [ - "process" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/6.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2025-02-07T04:58:58+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "5.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/e1367a453f0eda562eedb4f659e13aa900d66c53", - "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53", - "shasum": "" - }, - "require": { - "php": ">=8.3" - }, - "require-dev": { - "phpunit/phpunit": "^12.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "5.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/5.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2025-02-07T04:59:16+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "8.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", - "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", - "shasum": "" - }, - "require": { - "php": ">=8.3" - }, - "require-dev": { - "phpunit/phpunit": "^12.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "8.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "security": "https://github.com/sebastianbergmann/php-timer/security/policy", - "source": "https://github.com/sebastianbergmann/php-timer/tree/8.0.0" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2025-02-07T04:59:38+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "12.4.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "f62aab5794e36ccd26860db2d1bbf89ac19028d9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f62aab5794e36ccd26860db2d1bbf89ac19028d9", - "reference": "f62aab5794e36ccd26860db2d1bbf89ac19028d9", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.13.4", - "phar-io/manifest": "^2.0.4", - "phar-io/version": "^3.2.1", - "php": ">=8.3", - "phpunit/php-code-coverage": "^12.4.0", - "phpunit/php-file-iterator": "^6.0.0", - "phpunit/php-invoker": "^6.0.0", - "phpunit/php-text-template": "^5.0.0", - "phpunit/php-timer": "^8.0.0", - "sebastian/cli-parser": "^4.2.0", - "sebastian/comparator": "^7.1.3", - "sebastian/diff": "^7.0.0", - "sebastian/environment": "^8.0.3", - "sebastian/exporter": "^7.0.2", - "sebastian/global-state": "^8.0.2", - "sebastian/object-enumerator": "^7.0.0", - "sebastian/type": "^6.0.3", - "sebastian/version": "^6.0.0", - "staabm/side-effects-detector": "^1.0.5" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "12.4-dev" - } - }, - "autoload": { - "files": [ - "src/Framework/Assert/Functions.php" - ], - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/12.4.0" - }, - "funding": [ - { - "url": "https://phpunit.de/sponsors.html", - "type": "custom" - }, - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - }, - { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" - }, - { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", - "type": "tidelift" - } - ], - "time": "2025-10-03T04:28:03+00:00" - }, - { - "name": "psr/container", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", - "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", - "shasum": "" - }, - "require": { - "php": ">=7.4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Container\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", - "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" - ], - "support": { - "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/2.0.2" - }, - "time": "2021-11-05T16:47:00+00:00" - }, - { - "name": "psr/http-factory", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-factory.git", - "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", - "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", - "shasum": "" - }, - "require": { - "php": ">=7.1", - "psr/http-message": "^1.0 || ^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", - "keywords": [ - "factory", - "http", - "message", - "psr", - "psr-17", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-factory" - }, - "time": "2024-04-15T12:06:14+00:00" - }, - { - "name": "psr/http-message", - "version": "2.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-message/tree/2.0" - }, - "time": "2023-04-04T09:54:51+00:00" - }, - { - "name": "psr/log", - "version": "3.0.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", - "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "support": { - "source": "https://github.com/php-fig/log/tree/3.0.2" - }, - "time": "2024-09-11T13:17:53+00:00" - }, - { - "name": "psr/simple-cache", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/simple-cache.git", - "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", - "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\SimpleCache\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interfaces for simple caching", - "keywords": [ - "cache", - "caching", - "psr", - "psr-16", - "simple-cache" - ], - "support": { - "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" - }, - "time": "2021-10-29T13:26:27+00:00" - }, - { - "name": "rector/rector", - "version": "1.2.10", - "source": { - "type": "git", - "url": "https://github.com/rectorphp/rector.git", - "reference": "40f9cf38c05296bd32f444121336a521a293fa61" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/rectorphp/rector/zipball/40f9cf38c05296bd32f444121336a521a293fa61", - "reference": "40f9cf38c05296bd32f444121336a521a293fa61", - "shasum": "" - }, - "require": { - "php": "^7.2|^8.0", - "phpstan/phpstan": "^1.12.5" - }, - "conflict": { - "rector/rector-doctrine": "*", - "rector/rector-downgrade-php": "*", - "rector/rector-phpunit": "*", - "rector/rector-symfony": "*" - }, - "suggest": { - "ext-dom": "To manipulate phpunit.xml via the custom-rule command" - }, - "bin": [ - "bin/rector" - ], - "type": "library", - "autoload": { - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Instant Upgrade and Automated Refactoring of any PHP code", - "keywords": [ - "automation", - "dev", - "migration", - "refactoring" - ], - "support": { - "issues": "https://github.com/rectorphp/rector/issues", - "source": "https://github.com/rectorphp/rector/tree/1.2.10" - }, - "funding": [ - { - "url": "https://github.com/tomasvotruba", - "type": "github" - } - ], - "time": "2024-11-08T13:59:10+00:00" - }, - { - "name": "revolt/event-loop", - "version": "v1.0.7", - "source": { - "type": "git", - "url": "https://github.com/revoltphp/event-loop.git", - "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/revoltphp/event-loop/zipball/09bf1bf7f7f574453efe43044b06fafe12216eb3", - "reference": "09bf1bf7f7f574453efe43044b06fafe12216eb3", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "ext-json": "*", - "jetbrains/phpstorm-stubs": "^2019.3", - "phpunit/phpunit": "^9", - "psalm/phar": "^5.15" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Revolt\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Cees-Jan Kiewiet", - "email": "ceesjank@gmail.com" - }, - { - "name": "Christian Lück", - "email": "christian@clue.engineering" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - } - ], - "description": "Rock-solid event loop for concurrent PHP applications.", - "keywords": [ - "async", - "asynchronous", - "concurrency", - "event", - "event-loop", - "non-blocking", - "scheduler" - ], - "support": { - "issues": "https://github.com/revoltphp/event-loop/issues", - "source": "https://github.com/revoltphp/event-loop/tree/v1.0.7" - }, - "time": "2025-01-25T19:27:39+00:00" + ], + "time": "2025-03-13T15:25:07+00:00" }, { - "name": "sebastian/cli-parser", - "version": "4.2.0", + "name": "symfony/config", + "version": "v7.3.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "90f41072d220e5c40df6e8635f5dafba2d9d4d04" + "url": "https://github.com/symfony/config.git", + "reference": "8a09223170046d2cfda3d2e11af01df2c641e961" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/90f41072d220e5c40df6e8635f5dafba2d9d4d04", - "reference": "90f41072d220e5c40df6e8635f5dafba2d9d4d04", + "url": "https://api.github.com/repos/symfony/config/zipball/8a09223170046d2cfda3d2e11af01df2c641e961", + "reference": "8a09223170046d2cfda3d2e11af01df2c641e961", "shasum": "" }, "require": { - "php": ">=8.3" + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/filesystem": "^7.1", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/finder": "<6.4", + "symfony/service-contracts": "<2.5" }, "require-dev": { - "phpunit/phpunit": "^12.0" + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^6.4|^7.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "4.2-dev" - } - }, "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Library for parsing CLI options", - "homepage": "https://github.com/sebastianbergmann/cli-parser", + "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/4.2.0" + "source": "https://github.com/symfony/config/tree/v7.3.4" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", - "type": "github" + "url": "https://symfony.com/sponsor", + "type": "custom" }, { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" + "url": "https://github.com/fabpot", + "type": "github" }, { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" + "url": "https://github.com/nicolas-grekas", + "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/sebastian/cli-parser", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-09-14T09:36:45+00:00" + "time": "2025-09-22T12:46:16+00:00" }, { - "name": "sebastian/comparator", - "version": "7.1.3", + "name": "symfony/css-selector", + "version": "v7.3.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "dc904b4bb3ab070865fa4068cd84f3da8b945148" + "url": "https://github.com/symfony/css-selector.git", + "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/dc904b4bb3ab070865fa4068cd84f3da8b945148", - "reference": "dc904b4bb3ab070865fa4068cd84f3da8b945148", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/601a5ce9aaad7bf10797e3663faefce9e26c24e2", + "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-mbstring": "*", - "php": ">=8.3", - "sebastian/diff": "^7.0", - "sebastian/exporter": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^12.2" - }, - "suggest": { - "ext-bcmath": "For comparing BcMath\\Number objects" + "php": ">=8.2" }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "7.1-dev" - } - }, "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { - "name": "Volker Dusch", - "email": "github@wallbash.com" + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" }, { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "https://github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/sebastianbergmann/comparator/issues", - "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/7.1.3" + "source": "https://github.com/symfony/css-selector/tree/v7.3.0" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", - "type": "github" - }, - { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" + "url": "https://symfony.com/sponsor", + "type": "custom" }, { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" + "url": "https://github.com/fabpot", + "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-08-20T11:27:00+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { - "name": "sebastian/complexity", - "version": "5.0.0", + "name": "symfony/dependency-injection", + "version": "v7.3.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb" + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "82119812ab0bf3425c1234d413efd1b19bb92ae4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/bad4316aba5303d0221f43f8cee37eb58d384bbb", - "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/82119812ab0bf3425c1234d413efd1b19bb92ae4", + "reference": "82119812ab0bf3425c1234d413efd1b19bb92ae4", "shasum": "" }, "require": { - "nikic/php-parser": "^5.0", - "php": ">=8.3" + "php": ">=8.2", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/service-contracts": "^3.5", + "symfony/var-exporter": "^6.4.20|^7.2.5" + }, + "conflict": { + "ext-psr": "<1.1|>=2", + "symfony/config": "<6.4", + "symfony/finder": "<6.4", + "symfony/yaml": "<6.4" + }, + "provide": { + "psr/container-implementation": "1.1|2.0", + "symfony/service-implementation": "1.1|2.0|3.0" }, "require-dev": { - "phpunit/phpunit": "^12.0" + "symfony/config": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "5.0-dev" - } - }, "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Component\\DependencyInjection\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Library for calculating the complexity of PHP code units", - "homepage": "https://github.com/sebastianbergmann/complexity", + "description": "Allows you to standardize and centralize the way objects are constructed in your application", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/sebastianbergmann/complexity/issues", - "security": "https://github.com/sebastianbergmann/complexity/security/policy", - "source": "https://github.com/sebastianbergmann/complexity/tree/5.0.0" + "source": "https://github.com/symfony/dependency-injection/tree/v7.3.4" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "time": "2025-02-07T04:55:25+00:00" + "time": "2025-09-11T10:12:26+00:00" }, { - "name": "sebastian/diff", - "version": "7.0.0", + "name": "symfony/deprecation-contracts", + "version": "v3.6.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "7ab1ea946c012266ca32390913653d844ecd085f" + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f", - "reference": "7ab1ea946c012266ca32390913653d844ecd085f", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", "shasum": "" }, "require": { - "php": ">=8.3" - }, - "require-dev": { - "phpunit/phpunit": "^12.0", - "symfony/process": "^7.2" + "php": ">=8.1" }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { - "dev-main": "7.0-dev" + "dev-main": "3.6-dev" } }, "autoload": { - "classmap": [ - "src/" + "files": [ + "function.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff", - "udiff", - "unidiff", - "unified diff" - ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/sebastianbergmann/diff/issues", - "security": "https://github.com/sebastianbergmann/diff/security/policy", - "source": "https://github.com/sebastianbergmann/diff/tree/7.0.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "time": "2025-02-07T04:55:46+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { - "name": "sebastian/environment", - "version": "8.0.3", + "name": "symfony/dom-crawler", + "version": "v7.3.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "24a711b5c916efc6d6e62aa65aa2ec98fef77f68" + "url": "https://github.com/symfony/dom-crawler.git", + "reference": "efa076ea0eeff504383ff0dcf827ea5ce15690ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/24a711b5c916efc6d6e62aa65aa2ec98fef77f68", - "reference": "24a711b5c916efc6d6e62aa65aa2ec98fef77f68", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/efa076ea0eeff504383ff0dcf827ea5ce15690ba", + "reference": "efa076ea0eeff504383ff0dcf827ea5ce15690ba", "shasum": "" }, "require": { - "php": ">=8.3" + "masterminds/html5": "^2.6", + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { - "phpunit/phpunit": "^12.0" - }, - "suggest": { - "ext-posix": "*" + "symfony/css-selector": "^6.4|^7.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "8.0-dev" - } - }, "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Component\\DomCrawler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "https://github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], + "description": "Eases DOM navigation for HTML and XML documents", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/sebastianbergmann/environment/issues", - "security": "https://github.com/sebastianbergmann/environment/security/policy", - "source": "https://github.com/sebastianbergmann/environment/tree/8.0.3" + "source": "https://github.com/symfony/dom-crawler/tree/v7.3.3" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", - "type": "github" + "url": "https://symfony.com/sponsor", + "type": "custom" }, { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" + "url": "https://github.com/fabpot", + "type": "github" }, { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" + "url": "https://github.com/nicolas-grekas", + "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/sebastian/environment", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-08-12T14:11:56+00:00" + "time": "2025-08-06T20:13:54+00:00" }, { - "name": "sebastian/exporter", - "version": "7.0.2", + "name": "symfony/error-handler", + "version": "v7.3.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "016951ae10980765e4e7aee491eb288c64e505b7" + "url": "https://github.com/symfony/error-handler.git", + "reference": "99f81bc944ab8e5dae4f21b4ca9972698bbad0e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/016951ae10980765e4e7aee491eb288c64e505b7", - "reference": "016951ae10980765e4e7aee491eb288c64e505b7", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/99f81bc944ab8e5dae4f21b4ca9972698bbad0e4", + "reference": "99f81bc944ab8e5dae4f21b4ca9972698bbad0e4", "shasum": "" }, "require": { - "ext-mbstring": "*", - "php": ">=8.3", - "sebastian/recursion-context": "^7.0" + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/var-dumper": "^6.4|^7.0" + }, + "conflict": { + "symfony/deprecation-contracts": "<2.5", + "symfony/http-kernel": "<6.4" }, "require-dev": { - "phpunit/phpunit": "^12.0" + "symfony/console": "^6.4|^7.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/webpack-encore-bundle": "^1.0|^2.0" }, + "bin": [ + "Resources/bin/patch-type-declarations" + ], "type": "library", - "extra": { - "branch-alias": { - "dev-main": "7.0-dev" - } - }, "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "https://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], + "description": "Provides tools to manage errors and ease debugging PHP code", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/sebastianbergmann/exporter/issues", - "security": "https://github.com/sebastianbergmann/exporter/security/policy", - "source": "https://github.com/sebastianbergmann/exporter/tree/7.0.2" + "source": "https://github.com/symfony/error-handler/tree/v7.3.4" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", - "type": "github" + "url": "https://symfony.com/sponsor", + "type": "custom" }, { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" + "url": "https://github.com/fabpot", + "type": "github" }, { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" + "url": "https://github.com/nicolas-grekas", + "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-09-24T06:16:11+00:00" + "time": "2025-09-11T10:12:26+00:00" }, { - "name": "sebastian/global-state", - "version": "8.0.2", + "name": "symfony/event-dispatcher", + "version": "v7.3.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "ef1377171613d09edd25b7816f05be8313f9115d" + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/ef1377171613d09edd25b7816f05be8313f9115d", - "reference": "ef1377171613d09edd25b7816f05be8313f9115d", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b7dc69e71de420ac04bc9ab830cf3ffebba48191", + "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191", "shasum": "" }, "require": { - "php": ">=8.3", - "sebastian/object-reflector": "^5.0", - "sebastian/recursion-context": "^7.0" + "php": ">=8.2", + "symfony/event-dispatcher-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" }, "require-dev": { - "ext-dom": "*", - "phpunit/phpunit": "^12.0" + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/error-handler": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^6.4|^7.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "8.0-dev" - } - }, "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Snapshotting of global state", - "homepage": "https://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/sebastianbergmann/global-state/issues", - "security": "https://github.com/sebastianbergmann/global-state/security/policy", - "source": "https://github.com/sebastianbergmann/global-state/tree/8.0.2" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.3" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", - "type": "github" + "url": "https://symfony.com/sponsor", + "type": "custom" }, { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" + "url": "https://github.com/fabpot", + "type": "github" }, { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" + "url": "https://github.com/nicolas-grekas", + "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-08-29T11:29:25+00:00" + "time": "2025-08-13T11:49:31+00:00" }, { - "name": "sebastian/lines-of-code", - "version": "4.0.0", + "name": "symfony/event-dispatcher-contracts", + "version": "v3.6.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f" + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/97ffee3bcfb5805568d6af7f0f893678fc076d2f", - "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586", "shasum": "" }, "require": { - "nikic/php-parser": "^5.0", - "php": ">=8.3" - }, - "require-dev": { - "phpunit/phpunit": "^12.0" + "php": ">=8.1", + "psr/event-dispatcher": "^1" }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { - "dev-main": "4.0-dev" + "dev-main": "3.6-dev" } }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Library for counting the lines of code in PHP source code", - "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], "support": { - "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/4.0.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "time": "2025-02-07T04:57:28+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { - "name": "sebastian/object-enumerator", - "version": "7.0.0", + "name": "symfony/filesystem", + "version": "v7.3.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894" + "url": "https://github.com/symfony/filesystem.git", + "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1effe8e9b8e068e9ae228e542d5d11b5d16db894", - "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/edcbb768a186b5c3f25d0643159a787d3e63b7fd", + "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd", "shasum": "" }, "require": { - "php": ">=8.3", - "sebastian/object-reflector": "^5.0", - "sebastian/recursion-context": "^7.0" + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8" }, "require-dev": { - "phpunit/phpunit": "^12.0" + "symfony/process": "^6.4|^7.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "7.0-dev" - } - }, "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Traverses array structures and object graphs to enumerate all referenced objects", - "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/7.0.0" + "source": "https://github.com/symfony/filesystem/tree/v7.3.2" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "time": "2025-02-07T04:57:48+00:00" + "time": "2025-07-07T08:17:47+00:00" }, { - "name": "sebastian/object-reflector", - "version": "5.0.0", + "name": "symfony/finder", + "version": "v7.3.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "4bfa827c969c98be1e527abd576533293c634f6a" + "url": "https://github.com/symfony/finder.git", + "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/4bfa827c969c98be1e527abd576533293c634f6a", - "reference": "4bfa827c969c98be1e527abd576533293c634f6a", + "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe", + "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe", "shasum": "" }, "require": { - "php": ">=8.3" + "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^12.0" + "symfony/filesystem": "^6.4|^7.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "5.0-dev" - } - }, "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Allows reflection of object attributes, including inherited and non-public ones", - "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/5.0.0" + "source": "https://github.com/symfony/finder/tree/v7.3.2" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "time": "2025-02-07T04:58:17+00:00" + "time": "2025-07-15T13:41:35+00:00" }, { - "name": "sebastian/recursion-context", - "version": "7.0.1", + "name": "symfony/framework-bundle", + "version": "v7.3.5", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c" + "url": "https://github.com/symfony/framework-bundle.git", + "reference": "ebd42b1fc2652b96d33520195ea0f6e55c36f09d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/0b01998a7d5b1f122911a66bebcb8d46f0c82d8c", - "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/ebd42b1fc2652b96d33520195ea0f6e55c36f09d", + "reference": "ebd42b1fc2652b96d33520195ea0f6e55c36f09d", "shasum": "" }, "require": { - "php": ">=8.3" + "composer-runtime-api": ">=2.1", + "ext-xml": "*", + "php": ">=8.2", + "symfony/cache": "^6.4|^7.0", + "symfony/config": "^7.3", + "symfony/dependency-injection": "^7.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/error-handler": "^7.3", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/filesystem": "^7.1", + "symfony/finder": "^6.4|^7.0", + "symfony/http-foundation": "^7.3", + "symfony/http-kernel": "^7.2", + "symfony/polyfill-mbstring": "~1.0", + "symfony/routing": "^6.4|^7.0" }, - "require-dev": { - "phpunit/phpunit": "^12.0" + "conflict": { + "doctrine/persistence": "<1.3", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/asset": "<6.4", + "symfony/asset-mapper": "<6.4", + "symfony/clock": "<6.4", + "symfony/console": "<6.4", + "symfony/dom-crawler": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/form": "<6.4", + "symfony/http-client": "<6.4", + "symfony/json-streamer": ">=7.4", + "symfony/lock": "<6.4", + "symfony/mailer": "<6.4", + "symfony/messenger": "<6.4", + "symfony/mime": "<6.4", + "symfony/object-mapper": ">=7.4", + "symfony/property-access": "<6.4", + "symfony/property-info": "<6.4", + "symfony/runtime": "<6.4.13|>=7.0,<7.1.6", + "symfony/scheduler": "<6.4.4|>=7.0.0,<7.0.4", + "symfony/security-core": "<6.4", + "symfony/security-csrf": "<7.2", + "symfony/serializer": "<7.2.5", + "symfony/stopwatch": "<6.4", + "symfony/translation": "<7.3", + "symfony/twig-bridge": "<6.4", + "symfony/twig-bundle": "<6.4", + "symfony/validator": "<6.4", + "symfony/web-profiler-bundle": "<6.4", + "symfony/webhook": "<7.2", + "symfony/workflow": "<7.3.0-beta2" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "7.0-dev" - } + "require-dev": { + "doctrine/persistence": "^1.3|^2|^3", + "dragonmantank/cron-expression": "^3.1", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "seld/jsonlint": "^1.10", + "symfony/asset": "^6.4|^7.0", + "symfony/asset-mapper": "^6.4|^7.0", + "symfony/browser-kit": "^6.4|^7.0", + "symfony/clock": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/css-selector": "^6.4|^7.0", + "symfony/dom-crawler": "^6.4|^7.0", + "symfony/dotenv": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/form": "^6.4|^7.0", + "symfony/html-sanitizer": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/json-streamer": "7.3.*", + "symfony/lock": "^6.4|^7.0", + "symfony/mailer": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/notifier": "^6.4|^7.0", + "symfony/object-mapper": "^v7.3.0-beta2", + "symfony/polyfill-intl-icu": "~1.0", + "symfony/process": "^6.4|^7.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/rate-limiter": "^6.4|^7.0", + "symfony/scheduler": "^6.4.4|^7.0.4", + "symfony/security-bundle": "^6.4|^7.0", + "symfony/semaphore": "^6.4|^7.0", + "symfony/serializer": "^7.2.5", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/string": "^6.4|^7.0", + "symfony/translation": "^7.3", + "symfony/twig-bundle": "^6.4|^7.0", + "symfony/type-info": "^7.1.8", + "symfony/uid": "^6.4|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/web-link": "^6.4|^7.0", + "symfony/webhook": "^7.2", + "symfony/workflow": "^7.3", + "symfony/yaml": "^6.4|^7.0", + "twig/twig": "^3.12" }, + "type": "symfony-bundle", "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Bundle\\FrameworkBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { - "name": "Adam Harvey", - "email": "aharvey@php.net" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "https://github.com/sebastianbergmann/recursion-context", + "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/7.0.1" + "source": "https://github.com/symfony/framework-bundle/tree/v7.3.5" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", - "type": "github" + "url": "https://symfony.com/sponsor", + "type": "custom" }, { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" + "url": "https://github.com/fabpot", + "type": "github" }, { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" + "url": "https://github.com/nicolas-grekas", + "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-08-13T04:44:59+00:00" + "time": "2025-10-16T16:16:53+00:00" }, { - "name": "sebastian/type", - "version": "6.0.3", + "name": "symfony/http-client", + "version": "v7.3.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/type.git", - "reference": "e549163b9760b8f71f191651d22acf32d56d6d4d" + "url": "https://github.com/symfony/http-client.git", + "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/e549163b9760b8f71f191651d22acf32d56d6d4d", - "reference": "e549163b9760b8f71f191651d22acf32d56d6d4d", + "url": "https://api.github.com/repos/symfony/http-client/zipball/4b62871a01c49457cf2a8e560af7ee8a94b87a62", + "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62", "shasum": "" }, "require": { - "php": ">=8.3" + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-client-contracts": "~3.4.4|^3.5.2", + "symfony/polyfill-php83": "^1.29", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "amphp/amp": "<2.5", + "amphp/socket": "<1.1", + "php-http/discovery": "<1.15", + "symfony/http-foundation": "<6.4" + }, + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "1.0", + "symfony/http-client-implementation": "3.0" }, "require-dev": { - "phpunit/phpunit": "^12.0" + "amphp/http-client": "^4.2.1|^5.0", + "amphp/http-tunnel": "^1.0|^2.0", + "guzzlehttp/promises": "^1.4|^2.0", + "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", + "psr/http-client": "^1.0", + "symfony/amphp-http-client-meta": "^1.0|^2.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/rate-limiter": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "6.0-dev" - } - }, "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Component\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Collection of value objects that represent the types of the PHP type system", - "homepage": "https://github.com/sebastianbergmann/type", + "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", + "homepage": "https://symfony.com", + "keywords": [ + "http" + ], "support": { - "issues": "https://github.com/sebastianbergmann/type/issues", - "security": "https://github.com/sebastianbergmann/type/security/policy", - "source": "https://github.com/sebastianbergmann/type/tree/6.0.3" + "source": "https://github.com/symfony/http-client/tree/v7.3.4" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", - "type": "github" + "url": "https://symfony.com/sponsor", + "type": "custom" }, { - "url": "https://liberapay.com/sebastianbergmann", - "type": "liberapay" + "url": "https://github.com/fabpot", + "type": "github" }, { - "url": "https://thanks.dev/u/gh/sebastianbergmann", - "type": "thanks_dev" + "url": "https://github.com/nicolas-grekas", + "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/sebastian/type", + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-08-09T06:57:12+00:00" + "time": "2025-09-11T10:12:26+00:00" }, { - "name": "sebastian/version", - "version": "6.0.0", + "name": "symfony/http-client-contracts", + "version": "v3.6.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c" + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "75d7043853a42837e68111812f4d964b01e5101c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/3e6ccf7657d4f0a59200564b08cead899313b53c", - "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/75d7043853a42837e68111812f4d964b01e5101c", + "reference": "75d7043853a42837e68111812f4d964b01e5101c", "shasum": "" }, "require": { - "php": ">=8.3" + "php": ">=8.1" }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { - "dev-main": "6.0-dev" + "dev-main": "3.6-dev" } }, "autoload": { - "classmap": [ - "src/" + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Test/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], "support": { - "issues": "https://github.com/sebastianbergmann/version/issues", - "security": "https://github.com/sebastianbergmann/version/security/policy", - "source": "https://github.com/sebastianbergmann/version/tree/6.0.0" + "source": "https://github.com/symfony/http-client-contracts/tree/v3.6.0" }, "funding": [ { - "url": "https://github.com/sebastianbergmann", + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "time": "2025-02-07T05:00:38+00:00" + "time": "2025-04-29T11:18:49+00:00" }, { - "name": "staabm/side-effects-detector", - "version": "1.0.5", + "name": "symfony/http-foundation", + "version": "v7.3.5", "source": { "type": "git", - "url": "https://github.com/staabm/side-effects-detector.git", - "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + "url": "https://github.com/symfony/http-foundation.git", + "reference": "ce31218c7cac92eab280762c4375fb70a6f4f897" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", - "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ce31218c7cac92eab280762c4375fb70a6f4f897", + "reference": "ce31218c7cac92eab280762c4375fb70a6f4f897", "shasum": "" }, "require": { - "ext-tokenizer": "*", - "php": "^7.4 || ^8.0" + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php83": "^1.27" + }, + "conflict": { + "doctrine/dbal": "<3.6", + "symfony/cache": "<6.4.12|>=7.0,<7.1.5" }, "require-dev": { - "phpstan/extension-installer": "^1.4.3", - "phpstan/phpstan": "^1.12.6", - "phpunit/phpunit": "^9.6.21", - "symfony/var-dumper": "^5.4.43", - "tomasvotruba/type-coverage": "1.0.0", - "tomasvotruba/unused-public": "1.0.0" + "doctrine/dbal": "^3.6|^4", + "predis/predis": "^1.1|^2.0", + "symfony/cache": "^6.4.12|^7.1.5", + "symfony/clock": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/rate-limiter": "^6.4|^7.0" }, "type": "library", "autoload": { - "classmap": [ - "lib/" + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "A static analysis tool to detect side effects in PHP code", - "keywords": [ - "static analysis" + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } ], + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/staabm/side-effects-detector/issues", - "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + "source": "https://github.com/symfony/http-foundation/tree/v7.3.5" }, "funding": [ { - "url": "https://github.com/staabm", + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "time": "2024-10-20T05:08:20+00:00" + "time": "2025-10-24T21:42:11+00:00" }, { - "name": "symfony/console", - "version": "v7.3.4", + "name": "symfony/http-kernel", + "version": "v7.3.5", "source": { "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db" + "url": "https://github.com/symfony/http-kernel.git", + "reference": "24fd3f123532e26025f49f1abefcc01a69ef15ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/2b9c5fafbac0399a20a2e82429e2bd735dcfb7db", - "reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/24fd3f123532e26025f49f1abefcc01a69ef15ab", + "reference": "24fd3f123532e26025f49f1abefcc01a69ef15ab", "shasum": "" }, "require": { "php": ">=8.2", + "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-mbstring": "~1.0", - "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^7.2" + "symfony/error-handler": "^6.4|^7.0", + "symfony/event-dispatcher": "^7.3", + "symfony/http-foundation": "^7.3", + "symfony/polyfill-ctype": "^1.8" }, "conflict": { + "symfony/browser-kit": "<6.4", + "symfony/cache": "<6.4", + "symfony/config": "<6.4", + "symfony/console": "<6.4", "symfony/dependency-injection": "<6.4", - "symfony/dotenv": "<6.4", - "symfony/event-dispatcher": "<6.4", - "symfony/lock": "<6.4", - "symfony/process": "<6.4" + "symfony/doctrine-bridge": "<6.4", + "symfony/form": "<6.4", + "symfony/http-client": "<6.4", + "symfony/http-client-contracts": "<2.5", + "symfony/mailer": "<6.4", + "symfony/messenger": "<6.4", + "symfony/translation": "<6.4", + "symfony/translation-contracts": "<2.5", + "symfony/twig-bridge": "<6.4", + "symfony/validator": "<6.4", + "symfony/var-dumper": "<6.4", + "twig/twig": "<3.12" }, "provide": { "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { - "psr/log": "^1|^2|^3", + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^6.4|^7.0", + "symfony/clock": "^6.4|^7.0", "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/css-selector": "^6.4|^7.0", "symfony/dependency-injection": "^6.4|^7.0", - "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/lock": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", + "symfony/dom-crawler": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/http-client-contracts": "^2.5|^3", "symfony/process": "^6.4|^7.0", + "symfony/property-access": "^7.1", + "symfony/routing": "^6.4|^7.0", + "symfony/serializer": "^7.1", "symfony/stopwatch": "^6.4|^7.0", - "symfony/var-dumper": "^6.4|^7.0" + "symfony/translation": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3", + "symfony/uid": "^6.4|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0", + "symfony/var-exporter": "^6.4|^7.0", + "twig/twig": "^3.12" }, "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\Console\\": "" + "Symfony\\Component\\HttpKernel\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -4936,16 +3700,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Eases the creation of beautiful and testable command line interfaces", + "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", - "keywords": [ - "cli", - "command-line", - "console", - "terminal" - ], "support": { - "source": "https://github.com/symfony/console/tree/v7.3.4" + "source": "https://github.com/symfony/http-kernel/tree/v7.3.5" }, "funding": [ { @@ -4965,39 +3723,51 @@ "type": "tidelift" } ], - "time": "2025-09-22T15:31:00+00:00" + "time": "2025-10-28T10:19:01+00:00" }, { - "name": "symfony/deprecation-contracts", - "version": "v3.6.0", + "name": "symfony/panther", + "version": "v2.2.0", "source": { "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" + "url": "https://github.com/symfony/panther.git", + "reference": "b7e0f834c9046918972edb3dde2ecc4a20f6155e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", + "url": "https://api.github.com/repos/symfony/panther/zipball/b7e0f834c9046918972edb3dde2ecc4a20f6155e", + "reference": "b7e0f834c9046918972edb3dde2ecc4a20f6155e", "shasum": "" }, "require": { - "php": ">=8.1" + "ext-dom": "*", + "ext-libxml": "*", + "php": ">=8.0", + "php-webdriver/webdriver": "^1.8.2", + "symfony/browser-kit": "^5.4 || ^6.4 || ^7.0", + "symfony/dependency-injection": "^5.4 || ^6.4 || ^7.0", + "symfony/deprecation-contracts": "^2.4 || ^3", + "symfony/dom-crawler": "^5.4 || ^6.4 || ^7.0", + "symfony/http-client": "^6.4 || ^7.0", + "symfony/http-kernel": "^5.4 || ^6.4 || ^7.0", + "symfony/process": "^5.4 || ^6.4 || ^7.0" + }, + "require-dev": { + "symfony/css-selector": "^5.4 || ^6.4 || ^7.0", + "symfony/framework-bundle": "^5.4 || ^6.4 || ^7.0", + "symfony/mime": "^5.4 || ^6.4 || ^7.0", + "symfony/phpunit-bridge": "^7.2.0" }, "type": "library", "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, "branch-alias": { - "dev-main": "3.6-dev" + "dev-main": "2.0.x-dev" } }, "autoload": { - "files": [ - "function.php" - ] + "psr-4": { + "Symfony\\Component\\Panther\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5005,63 +3775,82 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Kévin Dunglas", + "email": "dunglas@gmail.com", + "homepage": "https://dunglas.fr" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com", + "description": "A browser testing and web scraping library for PHP and Symfony.", + "homepage": "https://dunglas.fr", + "keywords": [ + "e2e", + "scraping", + "selenium", + "symfony", + "testing", + "webdriver" + ], "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" + "issues": "https://github.com/symfony/panther/issues", + "source": "https://github.com/symfony/panther/tree/v2.2.0" }, "funding": [ { - "url": "https://symfony.com/sponsor", + "url": "https://www.panthera.org/donate", "type": "custom" }, { - "url": "https://github.com/fabpot", + "url": "https://github.com/dunglas", "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "url": "https://tidelift.com/funding/github/packagist/symfony/panther", "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2025-01-30T13:11:55+00:00" }, { - "name": "symfony/finder", - "version": "v7.3.2", + "name": "symfony/polyfill-ctype", + "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe" + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe", - "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { - "php": ">=8.2" + "php": ">=7.2" }, - "require-dev": { - "symfony/filesystem": "^6.4|^7.0" + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" }, "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { - "Symfony\\Component\\Finder\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Symfony\\Polyfill\\Ctype\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5069,18 +3858,24 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Finds files and directories via an intuitive fluent interface", + "description": "Symfony polyfill for ctype functions", "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], "support": { - "source": "https://github.com/symfony/finder/tree/v7.3.2" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" }, "funding": [ { @@ -5100,30 +3895,31 @@ "type": "tidelift" } ], - "time": "2025-07-15T13:41:35+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { - "name": "symfony/polyfill-ctype", + "name": "symfony/polyfill-mbstring", "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", "shasum": "" }, "require": { + "ext-iconv": "*", "php": ">=7.2" }, "provide": { - "ext-ctype": "*" + "ext-mbstring": "*" }, "suggest": { - "ext-ctype": "For best performance" + "ext-mbstring": "For best performance" }, "type": "library", "extra": { @@ -5137,7 +3933,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" + "Symfony\\Polyfill\\Mbstring\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -5146,24 +3942,25 @@ ], "authors": [ { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for ctype functions", + "description": "Symfony polyfill for the Mbstring extension", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "ctype", + "mbstring", "polyfill", - "portable" + "portable", + "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" }, "funding": [ { @@ -5183,28 +3980,25 @@ "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2024-12-23T08:48:59+00:00" }, { - "name": "symfony/polyfill-intl-grapheme", + "name": "symfony/polyfill-php80", "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", - "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", "shasum": "" }, "require": { "php": ">=7.2" }, - "suggest": { - "ext-intl": "For best performance" - }, "type": "library", "extra": { "thanks": { @@ -5217,14 +4011,21 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Intl\\Grapheme\\": "" - } + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, { "name": "Nicolas Grekas", "email": "p@tchwork.com" @@ -5234,18 +4035,16 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for intl's grapheme_* functions", + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "grapheme", - "intl", "polyfill", "portable", "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" }, "funding": [ { @@ -5265,28 +4064,25 @@ "type": "tidelift" } ], - "time": "2025-06-27T09:58:17+00:00" + "time": "2025-01-02T08:10:11+00:00" }, { - "name": "symfony/polyfill-intl-normalizer", + "name": "symfony/polyfill-php81", "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "3833d7255cc303546435cb650316bff708a1c75c" + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", - "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", "shasum": "" }, "require": { "php": ">=7.2" }, - "suggest": { - "ext-intl": "For best performance" - }, "type": "library", "extra": { "thanks": { @@ -5299,7 +4095,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + "Symfony\\Polyfill\\Php81\\": "" }, "classmap": [ "Resources/stubs" @@ -5319,18 +4115,16 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for intl's Normalizer class and related functions", + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "intl", - "normalizer", "polyfill", "portable", "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0" }, "funding": [ { @@ -5353,29 +4147,22 @@ "time": "2024-09-09T11:45:10+00:00" }, { - "name": "symfony/polyfill-mbstring", + "name": "symfony/polyfill-php83", "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", "shasum": "" }, "require": { - "ext-iconv": "*", "php": ">=7.2" }, - "provide": { - "ext-mbstring": "*" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, "type": "library", "extra": { "thanks": { @@ -5388,8 +4175,11 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - } + "Symfony\\Polyfill\\Php83\\": "" + }, + "classmap": [ + "Resources/stubs" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5405,17 +4195,16 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for the Mbstring extension", + "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "mbstring", "polyfill", "portable", "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" }, "funding": [ { @@ -5435,7 +4224,7 @@ "type": "tidelift" } ], - "time": "2024-12-23T08:48:59+00:00" + "time": "2025-07-08T02:45:35+00:00" }, { "name": "symfony/process", @@ -5503,43 +4292,43 @@ "time": "2025-09-11T10:12:26+00:00" }, { - "name": "symfony/service-contracts", - "version": "v3.6.0", + "name": "symfony/routing", + "version": "v7.3.4", "source": { "type": "git", - "url": "https://github.com/symfony/service-contracts.git", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" + "url": "https://github.com/symfony/routing.git", + "reference": "8dc648e159e9bac02b703b9fbd937f19ba13d07c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "url": "https://api.github.com/repos/symfony/routing/zipball/8dc648e159e9bac02b703b9fbd937f19ba13d07c", + "reference": "8dc648e159e9bac02b703b9fbd937f19ba13d07c", "shasum": "" }, "require": { - "php": ">=8.1", - "psr/container": "^1.1|^2.0", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { - "ext-psr": "<1.1|>=2" + "symfony/config": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/yaml": "<6.4" }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.6-dev" - } + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0" }, + "type": "library", "autoload": { "psr-4": { - "Symfony\\Contracts\\Service\\": "" + "Symfony\\Component\\Routing\\": "" }, "exclude-from-classmap": [ - "/Test/" + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -5548,26 +4337,24 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Generic abstractions related to writing services", + "description": "Maps an HTTP request to a set of configuration variables", "homepage": "https://symfony.com", "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" + "router", + "routing", + "uri", + "url" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/routing/tree/v7.3.4" }, "funding": [ { @@ -5578,54 +4365,55 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-25T09:37:31+00:00" + "time": "2025-09-11T10:12:26+00:00" }, { - "name": "symfony/string", - "version": "v7.3.4", + "name": "symfony/service-contracts", + "version": "v3.6.0", "source": { "type": "git", - "url": "https://github.com/symfony/string.git", - "reference": "f96476035142921000338bad71e5247fbc138872" + "url": "https://github.com/symfony/service-contracts.git", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f96476035142921000338bad71e5247fbc138872", - "reference": "f96476035142921000338bad71e5247fbc138872", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", "shasum": "" }, "require": { - "php": ">=8.2", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", - "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0" + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { - "symfony/translation-contracts": "<2.5" - }, - "require-dev": { - "symfony/emoji": "^7.1", - "symfony/http-client": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", - "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.4|^7.0" + "ext-psr": "<1.1|>=2" }, "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, "autoload": { - "files": [ - "Resources/functions.php" - ], "psr-4": { - "Symfony\\Component\\String\\": "" + "Symfony\\Contracts\\Service\\": "" }, "exclude-from-classmap": [ - "/Tests/" + "/Test/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -5642,18 +4430,18 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "description": "Generic abstractions related to writing services", "homepage": "https://symfony.com", "keywords": [ - "grapheme", - "i18n", - "string", - "unicode", - "utf-8", - "utf8" + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.3.4" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" }, "funding": [ { @@ -5664,16 +4452,12 @@ "url": "https://github.com/fabpot", "type": "github" }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-09-11T14:36:48+00:00" + "time": "2025-04-25T09:37:31+00:00" }, { "name": "symfony/var-dumper", @@ -5763,35 +4547,36 @@ "time": "2025-09-11T10:12:26+00:00" }, { - "name": "ta-tikoma/phpunit-architecture-test", - "version": "0.8.5", + "name": "symfony/var-exporter", + "version": "v7.3.4", "source": { "type": "git", - "url": "https://github.com/ta-tikoma/phpunit-architecture-test.git", - "reference": "cf6fb197b676ba716837c886baca842e4db29005" + "url": "https://github.com/symfony/var-exporter.git", + "reference": "0f020b544a30a7fe8ba972e53ee48a74c0bc87f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ta-tikoma/phpunit-architecture-test/zipball/cf6fb197b676ba716837c886baca842e4db29005", - "reference": "cf6fb197b676ba716837c886baca842e4db29005", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/0f020b544a30a7fe8ba972e53ee48a74c0bc87f4", + "reference": "0f020b544a30a7fe8ba972e53ee48a74c0bc87f4", "shasum": "" }, "require": { - "nikic/php-parser": "^4.18.0 || ^5.0.0", - "php": "^8.1.0", - "phpdocumentor/reflection-docblock": "^5.3.0", - "phpunit/phpunit": "^10.5.5 || ^11.0.0 || ^12.0.0", - "symfony/finder": "^6.4.0 || ^7.0.0" + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" }, "require-dev": { - "laravel/pint": "^1.13.7", - "phpstan/phpstan": "^1.10.52" + "symfony/property-access": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" }, "type": "library", "autoload": { "psr-4": { - "PHPUnit\\Architecture\\": "src/" - } + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5799,27 +4584,48 @@ ], "authors": [ { - "name": "Ni Shi", - "email": "futik0ma011@gmail.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { - "name": "Nuno Maduro", - "email": "enunomaduro@gmail.com" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Methods for testing application architecture", + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", "keywords": [ - "architecture", - "phpunit", - "stucture", - "test", - "testing" + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "lazy-loading", + "proxy", + "serialize" ], "support": { - "issues": "https://github.com/ta-tikoma/phpunit-architecture-test/issues", - "source": "https://github.com/ta-tikoma/phpunit-architecture-test/tree/0.8.5" + "source": "https://github.com/symfony/var-exporter/tree/v7.3.4" }, - "time": "2025-04-20T20:23:40+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-09-11T10:12:26+00:00" }, { "name": "theseer/tokenizer", @@ -5872,39 +4678,167 @@ "time": "2024-03-03T12:36:25+00:00" }, { - "name": "webmozart/assert", - "version": "1.12.0", + "name": "zenstruck/assert", + "version": "v1.6.0", "source": { "type": "git", - "url": "https://github.com/webmozarts/assert.git", - "reference": "541057574806f942c94662b817a50f63f7345360" + "url": "https://github.com/zenstruck/assert.git", + "reference": "f333d554e9f8e275e221f5b27bdbdc1b0aadbf02" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/541057574806f942c94662b817a50f63f7345360", - "reference": "541057574806f942c94662b817a50f63f7345360", + "url": "https://api.github.com/repos/zenstruck/assert/zipball/f333d554e9f8e275e221f5b27bdbdc1b0aadbf02", + "reference": "f333d554e9f8e275e221f5b27bdbdc1b0aadbf02", "shasum": "" }, "require": { - "ext-ctype": "*", - "ext-date": "*", - "ext-filter": "*", - "php": "^7.2 || ^8.0" + "php": ">=8.0", + "symfony/polyfill-php81": "^1.23", + "symfony/var-exporter": "^5.4|^6.0|^7.0|^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.4", + "phpunit/phpunit": "^9.5.21", + "symfony/phpunit-bridge": "^6.3|^7.0|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Zenstruck\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Bond", + "email": "kevinbond@gmail.com" + } + ], + "description": "Standalone, lightweight, framework agnostic, test assertion library.", + "homepage": "https://github.com/zenstruck/assert", + "keywords": [ + "assertion", + "phpunit", + "test" + ], + "support": { + "issues": "https://github.com/zenstruck/assert/issues", + "source": "https://github.com/zenstruck/assert/tree/v1.6.0" + }, + "funding": [ + { + "url": "https://github.com/kbond", + "type": "github" + }, + { + "url": "https://github.com/nikophil", + "type": "github" + } + ], + "time": "2025-11-02T14:41:16+00:00" + }, + { + "name": "zenstruck/browser", + "version": "v1.9.1", + "source": { + "type": "git", + "url": "https://github.com/zenstruck/browser.git", + "reference": "a1518531749b157347de60eef2a0a6f5fbd97b97" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zenstruck/browser/zipball/a1518531749b157347de60eef2a0a6f5fbd97b97", + "reference": "a1518531749b157347de60eef2a0a6f5fbd97b97", + "shasum": "" + }, + "require": { + "behat/mink": "^1.8", + "php": ">=8.0", + "symfony/browser-kit": "^5.4|^6.0|^7.0", + "symfony/css-selector": "^5.4|^6.0|^7.0", + "symfony/dom-crawler": "^5.4|^6.0|^7.0", + "symfony/framework-bundle": "^5.4|^6.0|^7.0", + "zenstruck/assert": "^1.1", + "zenstruck/callback": "^1.4.2" + }, + "require-dev": { + "dbrekelmans/bdi": "^1.0", + "justinrainbow/json-schema": "^5.3", + "mtdowling/jmespath.php": "^2.6", + "phpstan/phpstan": "^1.4", + "phpunit/phpunit": "^9.6.21|^10.4", + "symfony/mime": "^5.4|^6.0|^7.0", + "symfony/panther": "^1.1|^2.0.1", + "symfony/phpunit-bridge": "^6.0|^7.0", + "symfony/security-bundle": "^5.4|^6.0|^7.0" }, "suggest": { - "ext-intl": "", - "ext-simplexml": "", - "ext-spl": "" + "justinrainbow/json-schema": "Json schema validator. Needed to use Json::assertMatchesSchema().", + "mtdowling/jmespath.php": "PHP implementation for JMESPath. Needed to use Json assertions." }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10-dev" + "autoload": { + "psr-4": { + "Zenstruck\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Bond", + "email": "kevinbond@gmail.com" + } + ], + "description": "A fluent interface for your Symfony functional tests.", + "homepage": "https://github.com/zenstruck/browser", + "keywords": [ + "dev", + "symfony", + "test" + ], + "support": { + "issues": "https://github.com/zenstruck/browser/issues", + "source": "https://github.com/zenstruck/browser/tree/v1.9.1" + }, + "funding": [ + { + "url": "https://github.com/kbond", + "type": "github" } + ], + "time": "2024-11-05T12:21:53+00:00" + }, + { + "name": "zenstruck/callback", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/zenstruck/callback.git", + "reference": "eed9a532fd8974368e60c4a2550ed65eab7e5432" }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zenstruck/callback/zipball/eed9a532fd8974368e60c4a2550ed65eab7e5432", + "reference": "eed9a532fd8974368e60c4a2550ed65eab7e5432", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.14" + }, + "require-dev": { + "symfony/phpunit-bridge": "^5.2" + }, + "type": "library", "autoload": { "psr-4": { - "Webmozart\\Assert\\": "src/" + "Zenstruck\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -5913,21 +4847,28 @@ ], "authors": [ { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" + "name": "Kevin Bond", + "email": "kevinbond@gmail.com" } ], - "description": "Assertions to validate method input/output with nice error messages.", + "description": "Callable wrapper to validate and inject arguments.", + "homepage": "https://github.com/zenstruck/callback", "keywords": [ - "assert", - "check", - "validate" + "callable", + "callback", + "utility" ], "support": { - "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.12.0" + "issues": "https://github.com/zenstruck/callback/issues", + "source": "https://github.com/zenstruck/callback/tree/v1.5.0" }, - "time": "2025-10-20T12:43:39+00:00" + "funding": [ + { + "url": "https://github.com/kbond", + "type": "github" + } + ], + "time": "2022-08-31T14:56:15+00:00" } ], "aliases": [], diff --git a/phpunit.xml b/phpunit.xml index 35cdfbb..2296536 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -9,9 +9,11 @@ ./tests - - - src - - + + + + + + + diff --git a/tests/Browser/BrowserTestCase.php b/tests/Browser/BrowserTestCase.php new file mode 100644 index 0000000..b51e422 --- /dev/null +++ b/tests/Browser/BrowserTestCase.php @@ -0,0 +1,36 @@ +pantherBrowser() + ->visit('http://localhost:8100/wp-admin') + ->fillField('user_login', $login) + ->fillField('user_pass', $password) + ->click('wp-submit') + ->assertOn('http://localhost:8100/wp-admin/'); + } + + protected function asAdmin() + { + return $this->asUser('admin', 'admin'); + } + + protected function asAuthor() + { + return $this->asUser('author', 'author'); + } + + protected function asEditor() + { + return $this->asUser('editor', 'editor'); + } +} diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 06ff4ad..a7bac34 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -2,199 +2,19 @@ namespace Tests\Browser; -use function Tests\{asAdmin, asAuthor, asEditor}; - -const DEFAULT_SCRIPT_SELECTOR = 'script[src="https://scripts.simpleanalyticscdn.com/latest.js"]'; -const INACTIVE_ADMIN_SCRIPT_SELECTOR = 'script[src="http://localhost:8100/wp-content/plugins/simpleanalytics/resources/js/inactive.js"]'; -const INACTIVE_ADMIN_COMMENT = ''; -const NOSCRIPT_SELECTOR = 'noscript img[src="https://queue.simpleanalyticscdn.com/noscript.gif"][alt=""][referrerpolicy="no-referrer-when-downgrade"]'; - -it('can be activated', function () { - asAdmin() - ->navigate('http://localhost:8100/wp-admin/plugins.php') - ->assertPresent('tr[data-slug="simpleanalytics"]') - ->click('#activate-simpleanalytics') - ->assertPresent('a[href="options-general.php?page=simpleanalytics"]') - ->assertPresent('#deactivate-simpleanalytics') - ->screenshot(); -}); - -it('adds a script by default', function () { - visit('http://localhost:8100')->assertPresent(DEFAULT_SCRIPT_SELECTOR); -}); - -it('adds inactive script for authenticated users by default', function () { - asAdmin() - ->navigate('http://localhost:8100') - ->assertPresent('script[src="http://localhost:8100/wp-content/plugins/simpleanalytics/resources/js/inactive.js"]') - ->assertSourceHas(INACTIVE_ADMIN_COMMENT); -}); - -it('adds a script with ignored pages', function () { - asAdmin() - ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules') - ->fill('simpleanalytics_ignore_pages', '/vouchers') - ->click('Save Changes') - ->refresh() - ->assertValue('simpleanalytics_ignore_pages', '/vouchers') - ->screenshot(); - - visit('http://localhost:8100')->refresh()->assertSourceHas('data-ignore-pages="/vouchers"'); -}); - -it('adds inactive script for selected user roles', function () { - $admin = asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules') - ->check('simpleanalytics_exclude_user_roles-editor') - ->check('simpleanalytics_exclude_user_roles-author') - ->click('Save Changes') - ->assertChecked('simpleanalytics_exclude_user_roles-editor') - ->assertChecked('simpleanalytics_exclude_user_roles-author'); - - $admin->navigate('http://localhost:8100') - ->assertPresent(DEFAULT_SCRIPT_SELECTOR); - - asAuthor()->navigate('http://localhost:8100') - ->assertPresent(INACTIVE_ADMIN_SCRIPT_SELECTOR) - ->assertSourceHas(INACTIVE_ADMIN_COMMENT); - - asEditor()->navigate('http://localhost:8100') - ->assertPresent(INACTIVE_ADMIN_SCRIPT_SELECTOR) - ->assertSourceHas(INACTIVE_ADMIN_COMMENT); -}); - -it('adds a script with collect do not track enabled', function () { - asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') - ->check('simpleanalytics_collect_dnt') - ->click('Save Changes') - ->assertChecked('simpleanalytics_collect_dnt'); - - visit('http://localhost:8100')->assertSourceHas('data-collect-dnt="true"'); -}); - -it('adds a script with hash mode enabled', function () { - asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') - ->check('simpleanalytics_hash_mode') - ->click('Save Changes') - ->assertChecked('simpleanalytics_hash_mode'); - - visit('http://localhost:8100')->assertSourceHas('data-mode="hash"'); -}); - -it('adds a script with manually collect page views enabled', function () { - asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') - ->check('simpleanalytics_manual_collect') - ->click('Save Changes') - ->assertChecked('simpleanalytics_manual_collect'); - - visit('http://localhost:8100')->assertSourceHas('data-auto-collect="true"'); -}); - -/*it('adds noscript tag when support no javascript mode is enabled', function () { - asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') - ->check('simpleanalytics_noscript') - ->click('Save Changes') - ->assertChecked('simpleanalytics_noscript'); - - visit('http://localhost:8100')->assertPresent(NOSCRIPT_SELECTOR); -});*/ - -/*it('adds a script with onload callback', function () { - asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') - ->fill('simpleanalytics_onload_callback', 'sa_event("My event")') - ->click('Save Changes') - ->assertValue('simpleanalytics_onload_callback', 'sa_event("My event")'); - - visit('http://localhost:8100')->assertSourceHas('data-onload="sa_event(\"My event\")"'); -});*/ - -it('adds a script with overwrite domain name', function () { - asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') - ->fill('simpleanalytics_hostname', 'example.com') - ->click('Save Changes') - ->assertValue('simpleanalytics_hostname', 'example.com'); - - visit('http://localhost:8100')->assertSourceHas('data-hostname="example.com"'); -}); - -it('adds a script with global variable name', function () { - asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=advanced') - ->fill('simpleanalytics_sa_global', 'ba_event') - ->click('Save Changes') - ->assertValue('simpleanalytics_sa_global', 'ba_event'); - - visit('http://localhost:8100')->assertSourceHas('data-sa-global="ba_event"'); -}); - -it('adds automated events script when collect automated events is enabled', function () { - asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') - ->check('simpleanalytics_automated_events') - ->click('Save Changes') - ->assertChecked('simpleanalytics_automated_events'); - - visit('http://localhost:8100')->assertPresent('script[src="https://scripts.simpleanalyticscdn.com/auto-events.js"]'); -}); - -it('adds automated events script with auto collect downloads', function () { - asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') - ->check('simpleanalytics_automated_events') - ->fill('simpleanalytics_event_collect_downloads', 'outbound,emails,downloads') - ->click('Save Changes') - ->assertChecked('simpleanalytics_automated_events') - ->assertValue('simpleanalytics_event_collect_downloads', 'outbound,emails,downloads'); - - visit('http://localhost:8100')->assertSourceHas('data-collect="outbound,emails,downloads"'); -}); - -it('adds automated events script with download file extensions', function () { - asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') - ->check('simpleanalytics_automated_events') - ->fill('simpleanalytics_event_extensions', 'pdf,zip') - ->click('Save Changes') - ->assertChecked('simpleanalytics_automated_events') - ->assertValue('simpleanalytics_event_extensions', 'pdf,zip'); - - visit('http://localhost:8100')->assertSourceHas('data-extensions="pdf,zip"'); -}); - -it('adds automated events script with use titles of page enabled', function () { - asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') - ->check('simpleanalytics_automated_events') - ->check('simpleanalytics_event_use_title') - ->click('Save Changes') - ->assertChecked('simpleanalytics_automated_events') - ->assertChecked('simpleanalytics_event_use_title'); - - visit('http://localhost:8100')->assertSourceHas('data-use-title'); -}); - -it('adds automated events script with use full urls enabled', function () { - asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') - ->check('simpleanalytics_automated_events') - ->check('simpleanalytics_event_full_urls') - ->click('Save Changes') - ->assertChecked('simpleanalytics_automated_events') - ->assertChecked('simpleanalytics_event_full_urls'); - - visit('http://localhost:8100')->assertSourceHas('data-full-urls'); -}); - -it('adds automated events script with override global', function () { - asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=events') - ->check('simpleanalytics_automated_events') - ->fill('simpleanalytics_event_sa_global', 'ba_event') - ->click('Save Changes') - ->assertChecked('simpleanalytics_automated_events') - ->assertValue('simpleanalytics_event_sa_global', 'ba_event'); - - visit('http://localhost:8100')->assertSourceHas('data-sa-global="ba_event"'); -}); - -it('adds a script with a custom domain name', function () { - asAdmin() - ->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=general') - ->fill('simpleanalytics_custom_domain', 'mydomain.com') - ->click('Save Changes') - ->assertValue('simpleanalytics_custom_domain', 'mydomain.com'); - - visit('http://localhost:8100')->assertPresent('script[src="https://mydomain.com/latest.js"]'); -}); +class PluginSettingsTest extends BrowserTestCase +{ + public function test_activation_and_presence_of_default_scripts(): void + { + $this->asAdmin()->visit('http://localhost:8100/wp-admin/plugins.php') + ->click('#activate-simpleanalytics') + ->assertSeeElement('#deactivate-simpleanalytics') + ->visit('http://localhost:8100') + ->assertContains('') + ->assertContains(''); + } +} diff --git a/tests/Pest.php b/tests/Pest.php deleted file mode 100644 index c9a53fa..0000000 --- a/tests/Pest.php +++ /dev/null @@ -1,69 +0,0 @@ -extend(TestCase::class)->in('Feature'); -pest()->browser()->timeout(180000); - -/* -|-------------------------------------------------------------------------- -| Expectations -|-------------------------------------------------------------------------- -| -| When you're writing tests, you often need to check that values meet certain conditions. The -| "expect()" function gives you access to a set of "expectations" methods that you can use -| to assert different things. Of course, you may extend the Expectation API at any time. -| -*/ - -expect()->extend('toBeOne', function () { - return $this->toBe(1); -}); - -/* -|-------------------------------------------------------------------------- -| Functions -|-------------------------------------------------------------------------- -| -| While Pest is very powerful out-of-the-box, you may have some testing code specific to your -| project that you don't want to repeat in every file. Here you can also expose helpers as -| global functions to help you to reduce the number of lines of code in your test files. -| -*/ - -function asUser(string $login, string $password) -{ - return visit('http://localhost:8100/wp-admin') - ->fill('user_login', $login) - ->fill('user_pass', $password) - ->press('wp-submit') - ->assertUrlIs('http://localhost:8100/wp-admin'); -} - -function asAdmin() -{ - return asUser('admin', 'admin'); -} - -function asAuthor() -{ - return asUser('author', 'author'); -} - -function asEditor() -{ - return asUser('editor', 'editor'); -} diff --git a/tests/TestCase.php b/tests/TestCase.php index cfb05b6..690e86f 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -6,5 +6,4 @@ abstract class TestCase extends BaseTestCase { - // } diff --git a/tests/TestKernel.php b/tests/TestKernel.php new file mode 100644 index 0000000..a27a3c6 --- /dev/null +++ b/tests/TestKernel.php @@ -0,0 +1,24 @@ + Date: Mon, 3 Nov 2025 15:01:22 +0000 Subject: [PATCH 143/158] wip --- .github/workflows/tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5dd5218..2aac3d8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -129,6 +129,7 @@ jobs: wp user create author author@local.test --role=author --user_pass=author --path=/tmp/wp wp user create editor editor@local.test --role=editor --user_pass=editor --path=/tmp/wp wp user create subscriber subscriber@local.test --role=subscriber --user_pass=subscriber --path=/tmp/wp + mkdir public - name: Show current config values run: wp config list --path=/tmp/wp --allow-root From a38768f1b5e71b90770065ea4434c8f83bd6bbf0 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 4 Nov 2025 11:51:48 +0000 Subject: [PATCH 144/158] wip --- tests/Browser/BrowserTestCase.php | 8 +++++++- tests/Browser/PluginSettingsTest.php | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/Browser/BrowserTestCase.php b/tests/Browser/BrowserTestCase.php index b51e422..f7f6deb 100644 --- a/tests/Browser/BrowserTestCase.php +++ b/tests/Browser/BrowserTestCase.php @@ -3,15 +3,21 @@ namespace Tests\Browser; use Symfony\Component\Panther\PantherTestCase; +use Zenstruck\Browser\PantherBrowser; use Zenstruck\Browser\Test\HasBrowser; abstract class BrowserTestCase extends PantherTestCase { use HasBrowser; + protected function myBrowser(): PantherBrowser + { + return $this->pantherBrowser(['external_base_uri' => 'http://localhost:8100']); + } + protected function asUser($login, $password) { - return $this->pantherBrowser() + return $this->myBrowser() ->visit('http://localhost:8100/wp-admin') ->fillField('user_login', $login) ->fillField('user_pass', $password) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index a7bac34..0ae7638 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -13,7 +13,7 @@ public function test_activation_and_presence_of_default_scripts(): void ->assertContains('') ->assertContains(''); } From afd5b271475913166d012424db80ac283863c07f Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 4 Nov 2025 11:57:14 +0000 Subject: [PATCH 145/158] wip --- tests/Browser/PluginSettingsTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 0ae7638..6e9075f 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -6,15 +6,15 @@ class PluginSettingsTest extends BrowserTestCase { public function test_activation_and_presence_of_default_scripts(): void { - $this->asAdmin()->visit('http://localhost:8100/wp-admin/plugins.php') + $this->asAdmin()->visit('/wp-admin/plugins.php') ->click('#activate-simpleanalytics') ->assertSeeElement('#deactivate-simpleanalytics') - ->visit('http://localhost:8100') + ->visit('/') ->assertContains('') ->assertContains(''); } } From bc860a45c2e239d8134d9a540437f195b2bd0404 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 4 Nov 2025 11:57:49 +0000 Subject: [PATCH 146/158] wip --- .github/workflows/tests.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2aac3d8..5dd5218 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -129,7 +129,6 @@ jobs: wp user create author author@local.test --role=author --user_pass=author --path=/tmp/wp wp user create editor editor@local.test --role=editor --user_pass=editor --path=/tmp/wp wp user create subscriber subscriber@local.test --role=subscriber --user_pass=subscriber --path=/tmp/wp - mkdir public - name: Show current config values run: wp config list --path=/tmp/wp --allow-root From 219d96ec3623718d01c5229d06a78c42f375c26a Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 4 Nov 2025 12:47:25 +0000 Subject: [PATCH 147/158] wip --- .github/workflows/tests.yml | 3 +-- composer.json | 1 - composer.lock | 14 +++++++------- phpunit.xml | 4 ---- tests/Browser/BrowserTestCase.php | 6 ++++++ 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5dd5218..a3d6a9e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -164,8 +164,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: test-results-php${{ matrix.php }}-wp${{ matrix.wordpress }} - path: | - tests/Browser/Screenshots + path: var/browser retention-days: 30 - name: Show FrankenPHP logs diff --git a/composer.json b/composer.json index 144e66a..077a1c4 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,6 @@ { "require-dev": { "rector/rector": "^1.2", - "symfony/var-dumper": "^7.3", "zenstruck/browser": "^1.9", "phpunit/phpunit": "^12", "symfony/panther": "^2.2", diff --git a/composer.lock b/composer.lock index fba7461..a8be8be 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3c6e2e36603819c55446fde44c2a1fe1", + "content-hash": "038d4d3ecb67f10afe8c5937fe2778e4", "packages": [], "packages-dev": [ { @@ -4461,16 +4461,16 @@ }, { "name": "symfony/var-dumper", - "version": "v7.3.4", + "version": "v7.3.5", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb" + "reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb", - "reference": "b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/476c4ae17f43a9a36650c69879dcf5b1e6ae724d", + "reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d", "shasum": "" }, "require": { @@ -4524,7 +4524,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.3.4" + "source": "https://github.com/symfony/var-dumper/tree/v7.3.5" }, "funding": [ { @@ -4544,7 +4544,7 @@ "type": "tidelift" } ], - "time": "2025-09-11T10:12:26+00:00" + "time": "2025-09-27T09:00:46+00:00" }, { "name": "symfony/var-exporter", diff --git a/phpunit.xml b/phpunit.xml index 2296536..ae4dafb 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -12,8 +12,4 @@ - - - - diff --git a/tests/Browser/BrowserTestCase.php b/tests/Browser/BrowserTestCase.php index f7f6deb..34c0ba5 100644 --- a/tests/Browser/BrowserTestCase.php +++ b/tests/Browser/BrowserTestCase.php @@ -3,6 +3,7 @@ namespace Tests\Browser; use Symfony\Component\Panther\PantherTestCase; +use Tests\TestKernel; use Zenstruck\Browser\PantherBrowser; use Zenstruck\Browser\Test\HasBrowser; @@ -10,6 +11,11 @@ abstract class BrowserTestCase extends PantherTestCase { use HasBrowser; + protected static function getKernelClass(): string + { + return TestKernel::class; + } + protected function myBrowser(): PantherBrowser { return $this->pantherBrowser(['external_base_uri' => 'http://localhost:8100']); From 5b23f49ab4cfb856aa8d32f56b14d233f1567801 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 4 Nov 2025 12:47:43 +0000 Subject: [PATCH 148/158] wip --- tests/Browser/PluginSettingsTest.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 6e9075f..eed3469 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -17,4 +17,19 @@ public function test_activation_and_presence_of_default_scripts(): void ->visit('/') ->assertContains(''); } + + public function test_adds_script_with_ignored_pages(): void + { + $this->asAdmin() + ->pause() + ->visit('/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules') + ->fillField('simpleanalytics_ignore_pages', '/vouchers') + ->click('Save Changes') + ->visit('/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules') + ->assertFieldEquals('simpleanalytics_ignore_pages', '/vouchers'); + + $this->myBrowser() + ->visit('/') + ->assertContains('data-ignore-pages="/vouchers"'); + } } From a1ea9a61baa1d5eb11ef4552bca0b6c7b9d68632 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 4 Nov 2025 12:50:20 +0000 Subject: [PATCH 149/158] wip --- tests/Browser/PluginSettingsTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index eed3469..9e84548 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -20,8 +20,7 @@ public function test_activation_and_presence_of_default_scripts(): void public function test_adds_script_with_ignored_pages(): void { - $this->asAdmin() - ->pause() + $this->myBrowser() ->visit('/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules') ->fillField('simpleanalytics_ignore_pages', '/vouchers') ->click('Save Changes') From 75d5fe719780332ceb58c14b0e00749f429e0f3a Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 4 Nov 2025 12:54:33 +0000 Subject: [PATCH 150/158] wip --- tests/Browser/PluginSettingsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 9e84548..d898120 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -20,7 +20,7 @@ public function test_activation_and_presence_of_default_scripts(): void public function test_adds_script_with_ignored_pages(): void { - $this->myBrowser() + $this->asAdmin() ->visit('/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules') ->fillField('simpleanalytics_ignore_pages', '/vouchers') ->click('Save Changes') From a2f564d7e35fa0f33328069a3ba1ab65f987d5ed Mon Sep 17 00:00:00 2001 From: Adriaan van Rossum <1079135+adriaanvanrossum@users.noreply.github.com> Date: Fri, 28 Nov 2025 13:09:33 +0700 Subject: [PATCH 151/158] Try to fix the E2E test with AI in Opus 4.5 15s Run ./vendor/bin/phpunit ./vendor/bin/phpunit shell: /usr/bin/bash -e {0} env: WP_VERSION: 6.7 WP_SITE_URL: http://localhost:8100 WP_DB_NAME: wordpress WP_DB_USER: root WP_DB_PASS: root WP_DB_HOST: 127.0.0.1 COMPOSER_PROCESS_TIMEOUT: 0 COMPOSER_NO_INTERACTION: 1 COMPOSER_NO_AUDIT: 1 PNPM_HOME: /home/runner/setup-pnpm/node_modules/.bin PHPUnit 12.4.0 by Sebastian Bergmann and contributors. Runtime: PHP 8.4.14 Configuration: /home/runner/work/wordpress-plugin/wordpress-plugin/phpunit.xml .E 2 / 2 (100%) Saved Browser Artifacts: test_adds_script_with_ignored_pages Saved Source Files: * ./var/browser/source/error_Tests-Browser-PluginSettingsTest__test_adds_script_with_ignored_pages__0.html: Saved Console Logs: * ./var/browser/console-logs/error_Tests-Browser-PluginSettingsTest__test_adds_script_with_ignored_pages__0.log: Saved Screenshots: * ./var/browser/screenshots/error_Tests-Browser-PluginSettingsTest__test_adds_script_with_ignored_pages__0.png: Time: 00:14.918, Memory: 22.00 MB There was 1 error: 1) Tests\Browser\PluginSettingsTest::test_adds_script_with_ignored_pages Behat\Mink\Exception\ElementNotFoundException: Form field with id|name|label|value|placeholder "simpleanalytics_ignore_pages" not found. /home/runner/work/wordpress-plugin/wordpress-plugin/vendor/behat/mink/src/Element/TraversableElement.php:163 /home/runner/work/wordpress-plugin/wordpress-plugin/vendor/zenstruck/browser/src/Browser.php:214 /home/runner/work/wordpress-plugin/wordpress-plugin/tests/Browser/PluginSettingsTest.php:25 ERRORS! Tests: 2, Assertions: 6, Errors: 1. Error: Process completed with exit code 2. --- resources/css/settings.css | 7 +++++-- src/UI/PageLayoutComponent.php | 24 +++++------------------- tailwind.config.js | 1 + 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/resources/css/settings.css b/resources/css/settings.css index b63e5db..9360df7 100644 --- a/resources/css/settings.css +++ b/resources/css/settings.css @@ -1,5 +1,8 @@ @import url(https://fonts.bunny.net/css?family=space-grotesk:500,600); -@tailwind base; -@tailwind components; +.sa-settings { + @tailwind base; + @tailwind components; +} + @tailwind utilities; diff --git a/src/UI/PageLayoutComponent.php b/src/UI/PageLayoutComponent.php index 0a8d81c..f3e7d1a 100644 --- a/src/UI/PageLayoutComponent.php +++ b/src/UI/PageLayoutComponent.php @@ -31,9 +31,9 @@ public function __invoke(): void padding-left: 0; } - - + + Date: Fri, 28 Nov 2025 13:21:43 +0700 Subject: [PATCH 152/158] Fix Cursor bot bugs --- .github/workflows/tests.yml | 268 +++++++++++++-------------- tailwind.config.js | 29 ++- tests/Browser/PluginSettingsTest.php | 2 + 3 files changed, 148 insertions(+), 151 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a3d6a9e..59c67a3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,13 +12,13 @@ jobs: fail-fast: false matrix: # php: [ '7.4', '8.0', '8.1', '8.2' ] - php: [ '8.2', '8.3', '8.4' ] + php: ["8.2", "8.3", "8.4"] # wordpress: [ '5.9', '6.0', '6.3', '6.7', '6.8' ] - wordpress: [ '6.7', '6.8' ] + wordpress: ["6.7", "6.8"] exclude: # Exclude older PHP versions with newer WordPress - - php: '7.4' - wordpress: '6.5.3' + - php: "7.4" + wordpress: "6.5.3" services: mysql: @@ -26,7 +26,7 @@ jobs: env: MYSQL_DATABASE: wordpress MYSQL_ROOT_PASSWORD: root - ports: [ 3306:3306 ] + ports: [3306:3306] options: >- --health-cmd="mysqladmin ping -h 127.0.0.1 -uroot -proot" --health-interval=10s @@ -42,133 +42,133 @@ jobs: WP_DB_HOST: 127.0.0.1 steps: - - name: Check MySQL tables - run: | - echo "Listing databases:" - mysql -h 127.0.0.1 -uroot -proot -e "SHOW DATABASES;" - - echo "Checking if 'wordpress' database has any tables:" - mysql -h 127.0.0.1 -uroot -proot -D wordpress -e "SHOW TABLES;" || echo "No tables found (yet)." - - - name: Checkout plugin - uses: actions/checkout@v4 - - - name: Set up PHP - uses: shivammathur/setup-php@v2 - with: - # Note: Specified version is only for running tests, - # as the WordPress PHP version is set inside the FrankenPHP Dockerfile. - php-version: 8.4 - extensions: mysqli, zip, gd - coverage: none - tools: wp-cli - - - name: Cache WordPress archive - id: cache-wordpress - uses: actions/cache@v3 - with: - path: /tmp/wp - key: wp-${{ matrix.wordpress }} - - - name: Download WordPress - if: steps.cache-wordpress.outputs.cache-hit != 'true' - run: | - mkdir -p /tmp/wp - curl -O https://wordpress.org/wordpress-${WP_VERSION}.tar.gz - tar -xzf wordpress-${WP_VERSION}.tar.gz --strip-components=1 -C /tmp/wp - rm wordpress-${WP_VERSION}.tar.gz - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Build FrankenPHP image (with cache) - id: build - uses: docker/build-push-action@v6 - env: - DOCKER_BUILD_SUMMARY: false - with: - context: . - file: .github/docker/Dockerfile - tags: frankenphp-${{ matrix.php }} - load: true - build-args: | - PHP_VERSION=${{ matrix.php }} - cache-from: type=gha - cache-to: type=gha,mode=max - - - name: Start FrankenPHP server - run: | - docker run -d \ - --name frankenphp \ - --network host \ - -p 8100:8100 \ - -v /tmp/wp:/var/www/html \ - -v $GITHUB_WORKSPACE:/var/www/html/wp-content/plugins/simpleanalytics \ - -v $GITHUB_WORKSPACE/Caddyfile:/etc/frankenphp/Caddyfile \ - frankenphp-${{ matrix.php }} - - - name: Install WordPress - run: | - rm -f /tmp/wp/wp-config.php - wp config create \ - --dbname="$WP_DB_NAME" \ - --dbuser="$WP_DB_USER" \ - --dbpass="$WP_DB_PASS" \ - --dbhost="$WP_DB_HOST" \ - --path=/tmp/wp \ - --skip-check - wp core install \ - --url="${WP_SITE_URL}" \ - --title="Test Site" \ - --admin_user=admin \ - --admin_password=admin \ - --admin_email=test@example.com \ + - name: Check MySQL tables + run: | + echo "Listing databases:" + mysql -h 127.0.0.1 -uroot -proot -e "SHOW DATABASES;" + + echo "Checking if 'wordpress' database has any tables:" + mysql -h 127.0.0.1 -uroot -proot -D wordpress -e "SHOW TABLES;" || echo "No tables found (yet)." + + - name: Checkout plugin + uses: actions/checkout@v4 + + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + # Note: Specified version is only for running tests, + # as the WordPress PHP version is set inside the FrankenPHP Dockerfile. + php-version: 8.4 + extensions: mysqli, zip, gd + coverage: none + tools: wp-cli + + - name: Cache WordPress archive + id: cache-wordpress + uses: actions/cache@v3 + with: + path: /tmp/wp + key: wp-${{ matrix.wordpress }} + + - name: Download WordPress + if: steps.cache-wordpress.outputs.cache-hit != 'true' + run: | + mkdir -p /tmp/wp + curl -O https://wordpress.org/wordpress-${WP_VERSION}.tar.gz + tar -xzf wordpress-${WP_VERSION}.tar.gz --strip-components=1 -C /tmp/wp + rm wordpress-${WP_VERSION}.tar.gz + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build FrankenPHP image (with cache) + id: build + uses: docker/build-push-action@v6 + env: + DOCKER_BUILD_SUMMARY: false + with: + context: . + file: .github/docker/Dockerfile + tags: frankenphp-${{ matrix.php }} + load: true + build-args: | + PHP_VERSION=${{ matrix.php }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Start FrankenPHP server + run: | + docker run -d \ + --name frankenphp \ + --network host \ + -p 8100:8100 \ + -v /tmp/wp:/var/www/html \ + -v $GITHUB_WORKSPACE:/var/www/html/wp-content/plugins/simpleanalytics \ + -v $GITHUB_WORKSPACE/Caddyfile:/etc/frankenphp/Caddyfile \ + frankenphp-${{ matrix.php }} + + - name: Install WordPress + run: | + rm -f /tmp/wp/wp-config.php + wp config create \ + --dbname="$WP_DB_NAME" \ + --dbuser="$WP_DB_USER" \ + --dbpass="$WP_DB_PASS" \ + --dbhost="$WP_DB_HOST" \ --path=/tmp/wp \ - --skip-email \ - --allow-root - wp user create author author@local.test --role=author --user_pass=author --path=/tmp/wp - wp user create editor editor@local.test --role=editor --user_pass=editor --path=/tmp/wp - wp user create subscriber subscriber@local.test --role=subscriber --user_pass=subscriber --path=/tmp/wp - - - name: Show current config values - run: wp config list --path=/tmp/wp --allow-root - - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - version: 10 - - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: lts/* - cache: "pnpm" - - - name: Install pnpm dependencies - run: pnpm install - - - name: Cache composer dependencies - uses: actions/cache@v3 - with: - path: vendor - key: composer-${{ hashFiles('composer.lock') }} - - - name: Run composer install - run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist - - - name: Run Pest tests - run: ./vendor/bin/phpunit - - - name: Upload test results - if: always() - uses: actions/upload-artifact@v4 - with: - name: test-results-php${{ matrix.php }}-wp${{ matrix.wordpress }} - path: var/browser - retention-days: 30 - - - name: Show FrankenPHP logs - if: always() - run: | - echo "=== FrankenPHP logs ===" - docker logs frankenphp || echo "No logs found" + --skip-check + wp core install \ + --url="${WP_SITE_URL}" \ + --title="Test Site" \ + --admin_user=admin \ + --admin_password=admin \ + --admin_email=test@example.com \ + --path=/tmp/wp \ + --skip-email \ + --allow-root + wp user create author author@local.test --role=author --user_pass=author --path=/tmp/wp + wp user create editor editor@local.test --role=editor --user_pass=editor --path=/tmp/wp + wp user create subscriber subscriber@local.test --role=subscriber --user_pass=subscriber --path=/tmp/wp + + - name: Show current config values + run: wp config list --path=/tmp/wp --allow-root + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: lts/* + cache: "pnpm" + + - name: Install pnpm dependencies + run: pnpm install + + - name: Cache composer dependencies + uses: actions/cache@v3 + with: + path: vendor + key: composer-${{ hashFiles('composer.lock') }} + + - name: Run composer install + run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist + + - name: Run PHPUnit tests + run: ./vendor/bin/phpunit + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results-php${{ matrix.php }}-wp${{ matrix.wordpress }} + path: var/browser + retention-days: 30 + + - name: Show FrankenPHP logs + if: always() + run: | + echo "=== FrankenPHP logs ===" + docker logs frankenphp || echo "No logs found" diff --git a/tailwind.config.js b/tailwind.config.js index 6562269..76abc45 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,29 +1,24 @@ -import defaultTheme from 'tailwindcss/defaultTheme'; -import forms from '@tailwindcss/forms' +import defaultTheme from "tailwindcss/defaultTheme"; +import forms from "@tailwindcss/forms"; /** @type {import('tailwindcss').Config} */ module.exports = { - content: [ - './**/*.php', - ], - important: '.sa-settings', + content: ["./**/*.php"], + important: ".sa-settings", theme: { extend: { colors: { - primary: '#FF4F64', - primaryBg: '#eef9ff', - littleMuted: '#68797b', + primary: "#FF4F64", + primaryBg: "#eef9ff", + littleMuted: "#68797b", }, fontFamily: { - sans: ['Space Grotesk', ...defaultTheme.fontFamily.sans], + sans: ["Space Grotesk", ...defaultTheme.fontFamily.sans], }, borderWidth: { - 3: '3px', - } + 3: "3px", + }, }, }, - plugins: [ - forms(), - ], -} - + plugins: [forms()], +}; diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index d898120..6a75278 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -21,6 +21,8 @@ public function test_activation_and_presence_of_default_scripts(): void public function test_adds_script_with_ignored_pages(): void { $this->asAdmin() + ->visit('/wp-admin/plugins.php') + ->click('#activate-simpleanalytics') ->visit('/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules') ->fillField('simpleanalytics_ignore_pages', '/vouchers') ->click('Save Changes') From 97276aff18f5be62a2b054e542df65b8347ce15b Mon Sep 17 00:00:00 2001 From: Adriaan van Rossum <1079135+adriaanvanrossum@users.noreply.github.com> Date: Fri, 28 Nov 2025 13:23:56 +0700 Subject: [PATCH 153/158] Fix test isolation by ensuring plugin is activated before configuring settings The `test_adds_script_with_ignored_pages` test assumed the plugin was already active from a previous test, but PHPUnit tests run in isolation and execution order isn't guaranteed. - Add `activatePluginIfNeeded()` helper to BrowserTestCase that conditionally activates the plugin only if not already active - Update `test_adds_script_with_ignored_pages` to use the helper This ensures the test works regardless of execution order or whether the plugin is already activated. --- tests/Browser/BrowserTestCase.php | 13 +++++++++++++ tests/Browser/PluginSettingsTest.php | 8 ++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/tests/Browser/BrowserTestCase.php b/tests/Browser/BrowserTestCase.php index 34c0ba5..a39a3d5 100644 --- a/tests/Browser/BrowserTestCase.php +++ b/tests/Browser/BrowserTestCase.php @@ -45,4 +45,17 @@ protected function asEditor() { return $this->asUser('editor', 'editor'); } + + protected function activatePluginIfNeeded(PantherBrowser $browser): PantherBrowser + { + $browser->visit('/wp-admin/plugins.php'); + + $activateButton = $browser->crawler()->filter('#activate-simpleanalytics'); + + if ($activateButton->count() > 0) { + $browser->click('#activate-simpleanalytics'); + } + + return $browser; + } } diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 6a75278..5b29997 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -20,10 +20,10 @@ public function test_activation_and_presence_of_default_scripts(): void public function test_adds_script_with_ignored_pages(): void { - $this->asAdmin() - ->visit('/wp-admin/plugins.php') - ->click('#activate-simpleanalytics') - ->visit('/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules') + $browser = $this->asAdmin(); + $this->activatePluginIfNeeded($browser); + + $browser->visit('/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules') ->fillField('simpleanalytics_ignore_pages', '/vouchers') ->click('Save Changes') ->visit('/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules') From b8f3b22db7e073fed3651baa1e02e19138d75f60 Mon Sep 17 00:00:00 2001 From: Adriaan van Rossum <1079135+adriaanvanrossum@users.noreply.github.com> Date: Fri, 28 Nov 2025 13:25:55 +0700 Subject: [PATCH 154/158] Fail fast if one version already fails --- .github/workflows/tests.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 59c67a3..acc9ee5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -9,11 +9,9 @@ jobs: name: PHP ${{ matrix.php }} - WP ${{ matrix.wordpress }} runs-on: ubuntu-latest strategy: - fail-fast: false + fail-fast: true matrix: - # php: [ '7.4', '8.0', '8.1', '8.2' ] php: ["8.2", "8.3", "8.4"] - # wordpress: [ '5.9', '6.0', '6.3', '6.7', '6.8' ] wordpress: ["6.7", "6.8"] exclude: # Exclude older PHP versions with newer WordPress From 2d566f0b68f6726bef054eec36cdb427562b5c97 Mon Sep 17 00:00:00 2001 From: Adriaan van Rossum <1079135+adriaanvanrossum@users.noreply.github.com> Date: Fri, 28 Nov 2025 15:52:54 +0700 Subject: [PATCH 155/158] fix: use activatePluginIfNeeded in first test to prevent failures when plugin already active --- tests/Browser/PluginSettingsTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/Browser/PluginSettingsTest.php b/tests/Browser/PluginSettingsTest.php index 5b29997..15119c8 100644 --- a/tests/Browser/PluginSettingsTest.php +++ b/tests/Browser/PluginSettingsTest.php @@ -6,8 +6,10 @@ class PluginSettingsTest extends BrowserTestCase { public function test_activation_and_presence_of_default_scripts(): void { - $this->asAdmin()->visit('/wp-admin/plugins.php') - ->click('#activate-simpleanalytics') + $browser = $this->asAdmin(); + $this->activatePluginIfNeeded($browser); + + $browser->visit('/wp-admin/plugins.php') ->assertSeeElement('#deactivate-simpleanalytics') ->visit('/') ->assertContains('') From 71d0a9f6327762bc9b8e86cd0db23ee70ee58d27 Mon Sep 17 00:00:00 2001 From: Adriaan van Rossum <1079135+adriaanvanrossum@users.noreply.github.com> Date: Fri, 28 Nov 2025 15:55:16 +0700 Subject: [PATCH 156/158] fix: add missing --allow-root flag to wp user create commands --- .github/workflows/tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index acc9ee5..0df84f0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -124,9 +124,9 @@ jobs: --path=/tmp/wp \ --skip-email \ --allow-root - wp user create author author@local.test --role=author --user_pass=author --path=/tmp/wp - wp user create editor editor@local.test --role=editor --user_pass=editor --path=/tmp/wp - wp user create subscriber subscriber@local.test --role=subscriber --user_pass=subscriber --path=/tmp/wp + wp user create author author@local.test --role=author --user_pass=author --path=/tmp/wp --allow-root + wp user create editor editor@local.test --role=editor --user_pass=editor --path=/tmp/wp --allow-root + wp user create subscriber subscriber@local.test --role=subscriber --user_pass=subscriber --path=/tmp/wp --allow-root - name: Show current config values run: wp config list --path=/tmp/wp --allow-root From 1b75d2f58d81f981ceb1ec5c2aa62191a2fa6b45 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 9 Dec 2025 20:30:22 +0000 Subject: [PATCH 157/158] Formatting --- .github/workflows/tests.yml | 268 ++++++++++++++++++------------------ 1 file changed, 134 insertions(+), 134 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0df84f0..1105239 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,12 +11,12 @@ jobs: strategy: fail-fast: true matrix: - php: ["8.2", "8.3", "8.4"] - wordpress: ["6.7", "6.8"] + php: [ "8.2", "8.3", "8.4" ] + wordpress: [ "6.7", "6.8" ] exclude: # Exclude older PHP versions with newer WordPress - - php: "7.4" - wordpress: "6.5.3" + - php: "7.4" + wordpress: "6.5.3" services: mysql: @@ -24,7 +24,7 @@ jobs: env: MYSQL_DATABASE: wordpress MYSQL_ROOT_PASSWORD: root - ports: [3306:3306] + ports: [ 3306:3306 ] options: >- --health-cmd="mysqladmin ping -h 127.0.0.1 -uroot -proot" --health-interval=10s @@ -40,133 +40,133 @@ jobs: WP_DB_HOST: 127.0.0.1 steps: - - name: Check MySQL tables - run: | - echo "Listing databases:" - mysql -h 127.0.0.1 -uroot -proot -e "SHOW DATABASES;" - - echo "Checking if 'wordpress' database has any tables:" - mysql -h 127.0.0.1 -uroot -proot -D wordpress -e "SHOW TABLES;" || echo "No tables found (yet)." - - - name: Checkout plugin - uses: actions/checkout@v4 - - - name: Set up PHP - uses: shivammathur/setup-php@v2 - with: - # Note: Specified version is only for running tests, - # as the WordPress PHP version is set inside the FrankenPHP Dockerfile. - php-version: 8.4 - extensions: mysqli, zip, gd - coverage: none - tools: wp-cli - - - name: Cache WordPress archive - id: cache-wordpress - uses: actions/cache@v3 - with: - path: /tmp/wp - key: wp-${{ matrix.wordpress }} - - - name: Download WordPress - if: steps.cache-wordpress.outputs.cache-hit != 'true' - run: | - mkdir -p /tmp/wp - curl -O https://wordpress.org/wordpress-${WP_VERSION}.tar.gz - tar -xzf wordpress-${WP_VERSION}.tar.gz --strip-components=1 -C /tmp/wp - rm wordpress-${WP_VERSION}.tar.gz - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Build FrankenPHP image (with cache) - id: build - uses: docker/build-push-action@v6 - env: - DOCKER_BUILD_SUMMARY: false - with: - context: . - file: .github/docker/Dockerfile - tags: frankenphp-${{ matrix.php }} - load: true - build-args: | - PHP_VERSION=${{ matrix.php }} - cache-from: type=gha - cache-to: type=gha,mode=max - - - name: Start FrankenPHP server - run: | - docker run -d \ - --name frankenphp \ - --network host \ - -p 8100:8100 \ - -v /tmp/wp:/var/www/html \ - -v $GITHUB_WORKSPACE:/var/www/html/wp-content/plugins/simpleanalytics \ - -v $GITHUB_WORKSPACE/Caddyfile:/etc/frankenphp/Caddyfile \ - frankenphp-${{ matrix.php }} - - - name: Install WordPress - run: | - rm -f /tmp/wp/wp-config.php - wp config create \ - --dbname="$WP_DB_NAME" \ - --dbuser="$WP_DB_USER" \ - --dbpass="$WP_DB_PASS" \ - --dbhost="$WP_DB_HOST" \ + - name: Check MySQL tables + run: | + echo "Listing databases:" + mysql -h 127.0.0.1 -uroot -proot -e "SHOW DATABASES;" + + echo "Checking if 'wordpress' database has any tables:" + mysql -h 127.0.0.1 -uroot -proot -D wordpress -e "SHOW TABLES;" || echo "No tables found (yet)." + + - name: Checkout plugin + uses: actions/checkout@v4 + + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + # Note: Specified version is only for running tests, + # as the WordPress PHP version is set inside the FrankenPHP Dockerfile. + php-version: 8.4 + extensions: mysqli, zip, gd + coverage: none + tools: wp-cli + + - name: Cache WordPress archive + id: cache-wordpress + uses: actions/cache@v3 + with: + path: /tmp/wp + key: wp-${{ matrix.wordpress }} + + - name: Download WordPress + if: steps.cache-wordpress.outputs.cache-hit != 'true' + run: | + mkdir -p /tmp/wp + curl -O https://wordpress.org/wordpress-${WP_VERSION}.tar.gz + tar -xzf wordpress-${WP_VERSION}.tar.gz --strip-components=1 -C /tmp/wp + rm wordpress-${WP_VERSION}.tar.gz + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build FrankenPHP image (with cache) + id: build + uses: docker/build-push-action@v6 + env: + DOCKER_BUILD_SUMMARY: false + with: + context: . + file: .github/docker/Dockerfile + tags: frankenphp-${{ matrix.php }} + load: true + build-args: | + PHP_VERSION=${{ matrix.php }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Start FrankenPHP server + run: | + docker run -d \ + --name frankenphp \ + --network host \ + -p 8100:8100 \ + -v /tmp/wp:/var/www/html \ + -v $GITHUB_WORKSPACE:/var/www/html/wp-content/plugins/simpleanalytics \ + -v $GITHUB_WORKSPACE/Caddyfile:/etc/frankenphp/Caddyfile \ + frankenphp-${{ matrix.php }} + + - name: Install WordPress + run: | + rm -f /tmp/wp/wp-config.php + wp config create \ + --dbname="$WP_DB_NAME" \ + --dbuser="$WP_DB_USER" \ + --dbpass="$WP_DB_PASS" \ + --dbhost="$WP_DB_HOST" \ + --path=/tmp/wp \ + --skip-check + wp core install \ + --url="${WP_SITE_URL}" \ + --title="Test Site" \ + --admin_user=admin \ + --admin_password=admin \ + --admin_email=test@example.com \ --path=/tmp/wp \ - --skip-check - wp core install \ - --url="${WP_SITE_URL}" \ - --title="Test Site" \ - --admin_user=admin \ - --admin_password=admin \ - --admin_email=test@example.com \ - --path=/tmp/wp \ - --skip-email \ - --allow-root - wp user create author author@local.test --role=author --user_pass=author --path=/tmp/wp --allow-root - wp user create editor editor@local.test --role=editor --user_pass=editor --path=/tmp/wp --allow-root - wp user create subscriber subscriber@local.test --role=subscriber --user_pass=subscriber --path=/tmp/wp --allow-root - - - name: Show current config values - run: wp config list --path=/tmp/wp --allow-root - - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - version: 10 - - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: lts/* - cache: "pnpm" - - - name: Install pnpm dependencies - run: pnpm install - - - name: Cache composer dependencies - uses: actions/cache@v3 - with: - path: vendor - key: composer-${{ hashFiles('composer.lock') }} - - - name: Run composer install - run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist - - - name: Run PHPUnit tests - run: ./vendor/bin/phpunit - - - name: Upload test results - if: always() - uses: actions/upload-artifact@v4 - with: - name: test-results-php${{ matrix.php }}-wp${{ matrix.wordpress }} - path: var/browser - retention-days: 30 - - - name: Show FrankenPHP logs - if: always() - run: | - echo "=== FrankenPHP logs ===" - docker logs frankenphp || echo "No logs found" + --skip-email \ + --allow-root + wp user create author author@local.test --role=author --user_pass=author --path=/tmp/wp --allow-root + wp user create editor editor@local.test --role=editor --user_pass=editor --path=/tmp/wp --allow-root + wp user create subscriber subscriber@local.test --role=subscriber --user_pass=subscriber --path=/tmp/wp --allow-root + + - name: Show current config values + run: wp config list --path=/tmp/wp --allow-root + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: lts/* + cache: "pnpm" + + - name: Install pnpm dependencies + run: pnpm install + + - name: Cache composer dependencies + uses: actions/cache@v3 + with: + path: vendor + key: composer-${{ hashFiles('composer.lock') }} + + - name: Run composer install + run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist + + - name: Run PHPUnit tests + run: ./vendor/bin/phpunit + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results-php${{ matrix.php }}-wp${{ matrix.wordpress }} + path: var/browser + retention-days: 30 + + - name: Show FrankenPHP logs + if: always() + run: | + echo "=== FrankenPHP logs ===" + docker logs frankenphp || echo "No logs found" From 738670483a547a3eec0bab1f336246f6e40d30d1 Mon Sep 17 00:00:00 2001 From: Ostap Brehin Date: Tue, 9 Dec 2025 20:35:33 +0000 Subject: [PATCH 158/158] Revert "Try to fix the E2E test with AI in Opus 4.5" This reverts commit a2f564d7e35fa0f33328069a3ba1ab65f987d5ed. --- resources/css/settings.css | 7 ++----- src/UI/PageLayoutComponent.php | 24 +++++++++++++++++++----- tests/Browser/PluginSettingsTest.php | 21 +++++++++++++++++++++ 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/resources/css/settings.css b/resources/css/settings.css index 9360df7..b63e5db 100644 --- a/resources/css/settings.css +++ b/resources/css/settings.css @@ -1,8 +1,5 @@ @import url(https://fonts.bunny.net/css?family=space-grotesk:500,600); -.sa-settings { - @tailwind base; - @tailwind components; -} - +@tailwind base; +@tailwind components; @tailwind utilities; diff --git a/src/UI/PageLayoutComponent.php b/src/UI/PageLayoutComponent.php index f3e7d1a..0a8d81c 100644 --- a/src/UI/PageLayoutComponent.php +++ b/src/UI/PageLayoutComponent.php @@ -31,9 +31,9 @@ public function __invoke(): void padding-left: 0; } - - -
+ + visit('/') ->assertContains('data-ignore-pages="/vouchers"'); } + //it('adds inactive script for selected user roles', function () { + // $admin = asAdmin()->navigate('http://localhost:8100/wp-admin/options-general.php?page=simpleanalytics&tab=ignore-rules') + // ->check('simpleanalytics_exclude_user_roles-editor') + // ->check('simpleanalytics_exclude_user_roles-author') + // ->click('Save Changes') + // ->assertChecked('simpleanalytics_exclude_user_roles-editor') + // ->assertChecked('simpleanalytics_exclude_user_roles-author'); + // + // $admin->navigate('http://localhost:8100') + // ->assertPresent(DEFAULT_SCRIPT_SELECTOR); + // + // asAuthor()->navigate('http://localhost:8100') + // ->assertPresent(INACTIVE_ADMIN_SCRIPT_SELECTOR) + // ->assertSourceHas(INACTIVE_ADMIN_COMMENT); + // + // asEditor()->navigate('http://localhost:8100') + // ->assertPresent(INACTIVE_ADMIN_SCRIPT_SELECTOR) + // ->assertSourceHas(INACTIVE_ADMIN_COMMENT); + //}); + +// public function }