diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..f14a2c2 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,194 @@ +name: Tests + +on: + pull_request: + branches: [ master, v2 ] + push: + branches: [ master, v2 ] + +jobs: + # Craft 5.x tests (master branch) - PHP 8.2+ + craft5-tests: + if: github.ref == 'refs/heads/master' || github.base_ref == 'master' + runs-on: ubuntu-latest + + services: + postgres: + image: postgres:13-alpine + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + strategy: + matrix: + php: [8.2, 8.3] + + name: Craft 5.x - PHP ${{ matrix.php }} Tests + + steps: + - uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, pdo_pgsql, bcmath, soap, intl, gd, exif, iconv + coverage: xdebug + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v3 + with: + path: vendor + key: craft5-${{ runner.os }}-php-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }} + restore-keys: | + craft5-${{ runner.os }}-php-${{ matrix.php }}- + + - name: Install dependencies + run: composer install --prefer-dist --no-progress --dev + + - name: Setup test environment + run: | + cp tests/.env.example tests/.env + sed -i 's/host=postgres/host=localhost/' tests/.env + mkdir -p tests/_craft/storage/runtime + mkdir -p tests/_craft/storage/logs + mkdir -p tests/_craft/storage/config-deltas + mkdir -p tests/_craft/migrations + mkdir -p tests/_craft/translations + mkdir -p tests/_output + + - name: Build Codeception + run: vendor/bin/codecept build + + - name: Run all tests + run: vendor/bin/codecept run --coverage --coverage-xml + env: + CRAFT_DB_DSN: "pgsql:host=localhost;port=5432;dbname=postgres" + CRAFT_DB_USER: postgres + CRAFT_DB_PASSWORD: postgres + CRAFT_DB_SCHEMA: public + CRAFT_DB_TABLE_PREFIX: craft + CRAFT_SECURITY_KEY: test-security-key-for-github-actions + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v3 + if: matrix.php == '8.2' + with: + files: ./tests/_output/coverage.xml + fail_ci_if_error: false + verbose: true + + - name: Generate coverage text report + if: github.event_name == 'pull_request' && matrix.php == '8.2' + id: coverage + run: | + raw_output=$(vendor/bin/codecept run unit --coverage-text --no-ansi 2>&1) + + classes=$(echo "$raw_output" | grep "Classes:" | grep -o '[0-9]*\.[0-9]*%' | head -1 || echo "N/A") + methods=$(echo "$raw_output" | grep "Methods:" | grep -o '[0-9]*\.[0-9]*%' | head -1 || echo "N/A") + lines=$(echo "$raw_output" | grep "Lines:" | grep -o '[0-9]*\.[0-9]*%' | head -1 || echo "N/A") + + test_result=$(echo "$raw_output" | grep "OK (" || echo "Tests completed") + + echo "classes=${classes:-N/A}" >> "$GITHUB_OUTPUT" + echo "methods=${methods:-N/A}" >> "$GITHUB_OUTPUT" + echo "lines=${lines:-N/A}" >> "$GITHUB_OUTPUT" + echo "test-result=${test_result:-Tests completed}" >> "$GITHUB_OUTPUT" + env: + CRAFT_DB_DSN: "pgsql:host=localhost;port=5432;dbname=postgres" + CRAFT_DB_USER: postgres + CRAFT_DB_PASSWORD: postgres + CRAFT_DB_SCHEMA: public + CRAFT_DB_TABLE_PREFIX: craft + CRAFT_SECURITY_KEY: test-security-key-for-github-actions + + - name: Comment PR with coverage + uses: marocchino/sticky-pull-request-comment@v2 + if: github.event_name == 'pull_request' && matrix.php == '8.2' + with: + recreate: true + message: | + ## 📊 Test Coverage Report (PHP ${{ matrix.php }}) + + | Metric | Coverage | + |--------|----------| + | **Classes** | `${{ steps.coverage.outputs.classes }}` | + | **Methods** | `${{ steps.coverage.outputs.methods }}` | + | **Lines** | `${{ steps.coverage.outputs.lines }}` | + + **Test Results:** ${{ steps.coverage.outputs.test-result }} + + # Craft 4.x tests (v2 branch) - PHP 8.0+ + craft4-tests: + if: github.ref == 'refs/heads/v2' || github.base_ref == 'v2' + runs-on: ubuntu-latest + + strategy: + matrix: + php: [8.0, 8.1, 8.2] + + name: Craft 4.x - PHP ${{ matrix.php }} Tests + + steps: + - uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv + coverage: xdebug + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v3 + with: + path: vendor + key: craft4-${{ runner.os }}-php-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }} + restore-keys: | + craft4-${{ runner.os }}-php-${{ matrix.php }}- + + - name: Install dependencies + run: composer install --prefer-dist --no-progress --dev + + - name: Build Codeception (if exists) + run: | + if [ -f "vendor/bin/codecept" ]; then + vendor/bin/codecept build + fi + + - name: Run unit tests (if exists) + run: | + if [ -f "vendor/bin/codecept" ]; then + vendor/bin/codecept run unit + else + echo "No tests configured for this branch" + fi + + code-quality: + runs-on: ubuntu-latest + name: Code Quality + + steps: + - uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 8.2 + extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv + + - name: Install dependencies + run: composer install --prefer-dist --no-progress --dev + + - name: Check PHP syntax + run: find src tests -name "*.php" -exec php -l {} \; diff --git a/.gitignore b/.gitignore index a17970c..737f155 100755 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ # COMPOSER /vendor +composer.lock # BUILD FILES /bower_components/* @@ -30,3 +31,4 @@ !.vscode/extensions.json config.codekit3 prepros-6.config + diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..bed6c67 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,35 @@ +# Repository Guidelines + +## Project Structure & Module Organization +- `src/`: Plugin source code (controllers, models, asset bundles, templates, variables). +- `tests/`: Codeception suites (`unit/`, `functional/`) plus support data in `_support/` and `_data/`. +- `resources/`: Plugin resources and metadata assets. +- `vendor/`: Composer-managed dependencies (generated). + +## Build, Test, and Development Commands +- `composer install --dev`: Install runtime + dev dependencies for local development. +- `composer require wrav/simplesharing`: Install the plugin into a Craft project. +- `vendor/bin/codecept run`: Run all Codeception tests. +- `vendor/bin/codecept run unit`: Run unit tests only. +- `vendor/bin/codecept run functional`: Run functional tests only. +- `vendor/bin/codecept run --coverage`: Generate a coverage report. + +## Coding Style & Naming Conventions +- Language: PHP 8.2; Craft CMS plugin conventions. +- Autoloading: PSR-4 namespace `wrav\simplesharing\` mapped to `src/`. +- File naming: Class files match class names (e.g., `SimpleSharing.php`). +- Indentation: 4 spaces; keep files ASCII unless existing content requires Unicode. + +## Testing Guidelines +- Framework: Codeception (with PHPUnit under the hood). +- Suites: `unit` and `functional` are defined by `tests/*.suite.yml`. +- Naming: Place unit tests in `tests/unit` and functional tests in `tests/functional`; match Codeception naming conventions (e.g., `*Test.php`). +- Config: Set Craft test environment in `tests/_craft/config/test.php` before running functional tests. + +## Commit & Pull Request Guidelines +- Commits: Use short, imperative, sentence-case summaries (e.g., “Fix coverage summary extraction”); no prefix observed in recent history. +- PRs: Include a clear description, linked issue (if any), and test results. Add screenshots or recordings for Control Panel UI changes. + +## Security & Configuration Tips +- Do not commit secrets or `.env` files. Use local environment overrides only. +- Validate changes against Craft’s plugin requirements (`composer.json`) before release. diff --git a/CHANGELOG.md b/CHANGELOG.md index 2746d3d..a97b13d 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Simple Sharing Changelog +## 3.0.0 - 2026-01-14 +### Updated +- Craft5.x Support Added (^3.0.0 is not backward compatible with Craft4.x, use 2.x branch). +- Fixed LinkedIn sharing URL to use correct endpoint +- Updated Tumblr sharing URL format + +# Added +- Added support for functional, integration and unit testing + ## 2.0.0 - 2022-11-17 ### Updated - Craft4.x Support Added (^2.0.0 is not backward compatible with Craft3.x, use 1.x branch). diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..c5cfa28 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,65 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Simple Sharing is a Craft CMS 5.x plugin that generates social media share links within the Control Panel, allowing quick sharing of entries to Facebook, Twitter, LinkedIn, Mix, Tumblr, and Reddit. + +## Commands + +```bash +# Install dependencies +composer install --dev + +# Build Codeception (regenerate actor classes) +vendor/bin/codecept build + +# Check PHP syntax +find src tests -name "*.php" -exec php -l {} \; +``` + +### Running Tests (requires Docker) + +Tests require a PostgreSQL database. Use Docker Compose: + +```bash +# Setup test environment +cp tests/.env.example tests/.env + +# Start Docker containers +docker compose up -d + +# Access app container and run tests +docker exec -it app sh +vendor/bin/codecept run # All tests +vendor/bin/codecept run unit # Unit tests only +vendor/bin/codecept run integration # Integration tests only +vendor/bin/codecept run --coverage # With coverage +``` + +## Architecture + +**Plugin Structure** (`src/`): +- `SimpleSharing.php` - Main plugin class, registers Twig variable and injects CP JavaScript +- `variables/SimpleSharingVariable.php` - Twig variable providing `craft.simpleSharing.link(url, service)` +- `models/Settings.php` - Plugin settings (allowedSections, allowedPlatforms) +- `controllers/DefaultController.php` - Controller for CP actions (`actionUrl`) +- `assetbundles/simplesharing/` - JavaScript for CP sidebar functionality +- `templates/settings.twig` - Settings page template + +**Key Integration Points**: +- Registers `simpleSharing` variable on `CraftVariable::EVENT_INIT` +- Injects JavaScript on `View::EVENT_END_PAGE` for CP requests +- Extends `craft\base\Plugin` with settings model + +**Testing** (`tests/`): +- Uses Codeception with `unit`, `integration`, and `functional` suites +- Unit tests: Core functionality without Craft bootstrap +- Integration tests: Full Craft CMS integration with plugin installed +- Test config in `codeception.yml` with `\craft\test\Craft` module +- Database setup: `dbSetup: { clean: true, setupCraft: true }` + +## Supported Platforms + +facebook, twitter, linkedin, mix, tumblr, reddit diff --git a/README.md b/README.md index 163cdda..dcdfc8a 100755 --- a/README.md +++ b/README.md @@ -6,12 +6,16 @@ Simple Sharing is a CraftCMS plugin that generates social media share links with the Craft CP page, allowing you to quickly and easily share entries. ## Requirements -Current Version: 2.0.0\ -This plugin requires Craft CMS ^4.0.0. -If you are looking for CraftCMS 3.x support, use current project [Version 1.0.8](https://github.com/wrav/SimpleSharing/tree/1.0.8) +| Version | Craft CMS | PHP | +|---------|-----------|-----| +| ^3.0.0 | ^5.0.0 | ^8.2 | +| ^2.0.0 | ^4.0.0 | ^8.0.2 | +| ^1.0.0 | ^3.0.0 | ^7.2.5 | -If you are looking for CraftCMS 2.5 support, use previous project [version 1.1.5](https://github.com/hut6/SimpleSharing/tree/1.1.5) +If you are looking for CraftCMS 4.x support, use [Version 2.x](https://github.com/wrav/SimpleSharing/tree/v2) + +If you are looking for CraftCMS 3.x support, use [Version 1.0.8](https://github.com/wrav/SimpleSharing/tree/1.0.8) ## Installing @@ -40,6 +44,42 @@ Your able to generate share links on the fly in a template as followed. {{ craft.simpleSharing.link(url, 'reddit') }} ``` +## Testing + +The plugin includes a comprehensive test suite using Codeception with unit, integration, and functional tests. + +### Running Tests + +Tests require Docker with PostgreSQL: + +```bash +# Setup test environment +cp tests/.env.example tests/.env + +# Start Docker containers +docker compose up -d + +# Access app container +docker exec -it app sh + +# Run all tests +vendor/bin/codecept run + +# Run specific suites +vendor/bin/codecept run unit +vendor/bin/codecept run integration +vendor/bin/codecept run functional + +# Run with coverage report +vendor/bin/codecept run --coverage +``` + +### Test Coverage + +- **Unit Tests**: URL generation, input validation, platform support +- **Integration Tests**: Plugin installation, settings rendering, Craft integration +- **Functional Tests**: Template variable availability + ## Credits Original built while at working at [HutSix](https://hutsix.com.au/) I've since been granted permission to continue development here. diff --git a/codeception.yml b/codeception.yml new file mode 100644 index 0000000..c8d4275 --- /dev/null +++ b/codeception.yml @@ -0,0 +1,34 @@ +namespace: tests +actor: Tester +paths: + tests: tests + output: tests/_output + data: tests/_data + support: tests/_support + envs: tests/_envs +bootstrap: _bootstrap.php +params: + - tests/.env +modules: + enabled: + - \craft\test\Craft + config: + \craft\test\Craft: + configFile: "tests/_craft/config/test.php" + entryUrl: "https://localhost/index.php" + projectConfig: {} + migrations: [] + plugins: + simple-sharing: + class: '\wrav\simplesharing\SimpleSharing' + handle: simple-sharing + cleanup: true + transaction: true + dbSetup: { clean: true, setupCraft: true } +coverage: + enabled: true + include: + - src/* + exclude: + - tests/* + - src/assetbundles/* diff --git a/composer.json b/composer.json index 8afd465..bd7fa0d 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "wrav/simplesharing", "description": "Simple Sharing generates social media share links within CP entry pages, allowing you to quickly & easily share entries.", "type": "craft-plugin", - "version": "2.0.0", + "version": "3.0.0", "keywords": [ "craft", "cms", @@ -31,8 +31,9 @@ } ], "require": { - "php": ">=8.0.0", - "craftcms/cms": "^4.0.0" + "php": "^8.2", + "craftcms/cms": "^5.0.0", + "vlucas/phpdotenv": "^5.6" }, "repositories": [ { @@ -56,9 +57,18 @@ "class": "wrav\\simplesharing\\SimpleSharing" }, "config": { + "platform": { + "php": "8.2" + }, "allow-plugins": { "yiisoft/yii2-composer": true, "craftcms/plugin-installer": true } + }, + "require-dev": { + "phpunit/phpunit": "^11.4", + "codeception/module-yii2": "^1.1", + "codeception/module-phpbrowser": "^3.0", + "codeception/module-asserts": "^3.0" } } diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..7bf5b60 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,26 @@ +# Add postgres service for unit testing +services: + postgres: + image: postgres:13-alpine + container_name: postgres + ports: + - 5432:5432 + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + healthcheck: + test: ["CMD", "pg_isready", "-U", "postgres", "-d", "postgres"] + interval: 5s + retries: 3 + app: + image: craftcms/nginx:8.2-dev + container_name: app + environment: + XDEBUG_CONFIG: client_host=host.docker.internal + depends_on: + postgres: + condition: service_healthy + volumes: + - .:/app + # vendor/bin/codecept run \ No newline at end of file diff --git a/src/SimpleSharing.php b/src/SimpleSharing.php index f25a92d..3fe1b5d 100755 --- a/src/SimpleSharing.php +++ b/src/SimpleSharing.php @@ -1,6 +1,6 @@ sections->getAllSections(); + $sections = Craft::$app->entries->getAllSections(); $optionsSections = []; foreach ($sections as $section) { diff --git a/src/assetbundles/simplesharing/SimpleSharingAsset.php b/src/assetbundles/simplesharing/SimpleSharingAsset.php index a6ae02c..8f65056 100755 --- a/src/assetbundles/simplesharing/SimpleSharingAsset.php +++ b/src/assetbundles/simplesharing/SimpleSharingAsset.php @@ -1,6 +1,6 @@ 'Facebook', 'twitter' => 'Twitter', - 'linkedin' => 'LinkedIn', + 'linkedin' => 'LinkedIn', //'pinterest' => 'Pinterest', 'mix' => 'Mix', - 'tumblr' => 'Tumblr', + 'tumblr' => 'Tumblr', 'reddit' => 'Reddit', ]; diff --git a/src/models/Settings.php b/src/models/Settings.php index 24feec8..cf5cd4c 100755 --- a/src/models/Settings.php +++ b/src/models/Settings.php @@ -1,6 +1,6 @@ getenv('CRAFT_DB_DSN'), + 'user' => getenv('CRAFT_DB_USER'), + 'password' => getenv('CRAFT_DB_PASSWORD'), + 'schema' => getenv('CRAFT_DB_SCHEMA'), + 'tablePrefix' => getenv('CRAFT_DB_TABLE_PREFIX'), +]; diff --git a/tests/_craft/config/test.php b/tests/_craft/config/test.php new file mode 100644 index 0000000..a5b52b4 --- /dev/null +++ b/tests/_craft/config/test.php @@ -0,0 +1,5 @@ +amOnPage('?p=/'); + $I->seeResponseCodeIs(200); + } + + public function testPluginTwigVariableExists(FunctionalTester $I): void + { + // Test that the simpleSharing Twig variable is available + $I->amOnPage('?p=/'); + // This would need a test template that uses {{ craft.simpleSharing }} + $I->seeResponseCodeIs(200); + } +} diff --git a/tests/integration.suite.yml b/tests/integration.suite.yml new file mode 100644 index 0000000..6f689bc --- /dev/null +++ b/tests/integration.suite.yml @@ -0,0 +1,11 @@ +# Codeception Test Suite Configuration +# +# Suite for integration tests with Craft CMS bootstrapped + +actor: IntegrationTester +bootstrap: _bootstrap.php +modules: + enabled: + - Asserts + - \tests\Helper\Unit + step_decorators: ~ diff --git a/tests/integration/PluginIntegrationTest.php b/tests/integration/PluginIntegrationTest.php new file mode 100644 index 0000000..6b7fc5b --- /dev/null +++ b/tests/integration/PluginIntegrationTest.php @@ -0,0 +1,64 @@ +plugins->getPlugin('simple-sharing'); + + $this->assertNotNull($plugin); + $this->assertInstanceOf(SimpleSharing::class, $plugin); + } + + public function testSettingsModelHasCorrectDefaults(): void + { + $plugin = SimpleSharing::getInstance(); + $settings = $plugin->getSettings(); + + $this->assertInstanceOf(Settings::class, $settings); + $this->assertIsArray($settings->allowedSections); + $this->assertIsArray($settings->allowedPlatforms); + } + + public function testSettingsHtmlRendersWithSections(): void + { + $plugin = SimpleSharing::getInstance(); + + $reflection = new \ReflectionMethod($plugin, 'settingsHtml'); + $reflection->setAccessible(true); + + $html = $reflection->invoke($plugin); + + $this->assertIsString($html); + $this->assertStringContainsString('allowedSections', $html); + $this->assertStringContainsString('allowedPlatforms', $html); + + // Verify platform options are rendered + $this->assertStringContainsString('Facebook', $html); + $this->assertStringContainsString('Twitter', $html); + $this->assertStringContainsString('LinkedIn', $html); + } + + public function testSettingsHtmlIncludesSectionsFromCraft(): void + { + $sections = Craft::$app->entries->getAllSections(); + $plugin = SimpleSharing::getInstance(); + + $reflection = new \ReflectionMethod($plugin, 'settingsHtml'); + $reflection->setAccessible(true); + + $html = $reflection->invoke($plugin); + + // If there are sections in the system, they should appear in the settings + foreach ($sections as $section) { + $this->assertStringContainsString($section->name, $html); + } + } +} diff --git a/tests/integration/_bootstrap.php b/tests/integration/_bootstrap.php new file mode 100644 index 0000000..cac8ad0 --- /dev/null +++ b/tests/integration/_bootstrap.php @@ -0,0 +1,4 @@ +assertTrue(class_exists(SimpleSharing::class)); + } + + public function testPluginExtendsBasePlugin(): void + { + $reflection = new \ReflectionClass(SimpleSharing::class); + $this->assertTrue($reflection->isSubclassOf(\craft\base\Plugin::class)); + } + + public function testSettingsHtmlMethodExists(): void + { + $reflection = new \ReflectionClass(SimpleSharing::class); + + $this->assertTrue($reflection->hasMethod('settingsHtml')); + + $method = $reflection->getMethod('settingsHtml'); + $this->assertTrue($method->isProtected()); + $this->assertEquals('string', $method->getReturnType()->getName()); + } + + public function testCreateSettingsModelMethodExists(): void + { + $reflection = new \ReflectionClass(SimpleSharing::class); + + $this->assertTrue($reflection->hasMethod('createSettingsModel')); + + $method = $reflection->getMethod('createSettingsModel'); + $this->assertTrue($method->isProtected()); + } + +} diff --git a/tests/unit/SimpleSharingVariableTest.php b/tests/unit/SimpleSharingVariableTest.php new file mode 100644 index 0000000..a8b4d41 --- /dev/null +++ b/tests/unit/SimpleSharingVariableTest.php @@ -0,0 +1,109 @@ +variable = new SimpleSharingVariable(); + } + + public function testFacebookLink(): void + { + $url = 'https://example.com/test-page'; + $result = $this->variable->link($url, 'facebook'); + + $this->assertSame( + 'https://www.facebook.com/sharer/sharer.php?u=' . urlencode($url), + $result + ); + } + + public function testTwitterLink(): void + { + $url = 'https://example.com/test-page'; + $result = $this->variable->link($url, 'twitter'); + + $this->assertSame( + 'https://twitter.com/intent/tweet?text=' . urlencode($url), + $result + ); + } + + public function testLinkedInLink(): void + { + $url = 'https://example.com/test-page'; + $result = $this->variable->link($url, 'linkedin'); + + $this->assertSame( + 'https://www.linkedin.com/shareArticle?mini=true&title=&summary=&source=&url=' . urlencode($url), + $result + ); + } + + public function testMixLink(): void + { + $url = 'https://example.com/test-page'; + $result = $this->variable->link($url, 'mix'); + + $this->assertSame( + 'https://mix.com/add?url=' . urlencode($url), + $result + ); + } + + public function testTumblrLink(): void + { + $url = 'https://example.com/test-page'; + $result = $this->variable->link($url, 'tumblr'); + + $this->assertSame( + 'https://www.tumblr.com/share/link?url=' . urlencode($url), + $result + ); + } + + public function testRedditLink(): void + { + $url = 'https://example.com/test-page'; + $result = $this->variable->link($url, 'reddit'); + + $this->assertSame( + 'http://www.reddit.com/submit?url=' . urlencode($url), + $result + ); + } + + public function testUnsupportedService(): void + { + $url = 'https://example.com/test-page'; + $result = $this->variable->link($url, 'unsupported-service'); + + $this->assertNull($result); + } + + public function testEmptyUrl(): void + { + $result = $this->variable->link('', 'facebook'); + $this->assertNull($result); + + $result = $this->variable->link(' ', 'facebook'); + $this->assertNull($result); + } + + public function testUrlEncoding(): void + { + $url = 'https://example.com/test page with spaces & symbols'; + $result = $this->variable->link($url, 'facebook'); + + $this->assertStringContainsString(urlencode($url), $result); + $this->assertStringNotContainsString(' ', $result); + $this->assertStringNotContainsString('&', $result); + } +} \ No newline at end of file diff --git a/tests/unit/_bootstrap.php b/tests/unit/_bootstrap.php new file mode 100644 index 0000000..a814366 --- /dev/null +++ b/tests/unit/_bootstrap.php @@ -0,0 +1 @@ +