diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..ea58397
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,24 @@
+name: Tests
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+
+jobs:
+ phpunit:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ php-version: [ '7.4', '8.1', '8.3' ]
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php-version }}
+ coverage: pcov
+
+ - run: composer update --prefer-dist --no-progress
+
+ - run: vendor/bin/phpunit --coverage-text
diff --git a/.gitignore b/.gitignore
index 5469669..a74cbe5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,4 +45,9 @@ wp-config.php
#
# Note: If you wish to whitelist themes,
# uncomment the next line
-#/wp-content/themes
\ No newline at end of file
+#/wp-content/themes
+
+# Composer / PHPUnit
+/vendor/
+/composer.lock
+.phpunit.result.cache
diff --git a/README.md b/README.md
index dc62893..e53d36b 100644
--- a/README.md
+++ b/README.md
@@ -33,6 +33,14 @@ Paigaldus
2. Aktiveeri WordPressi adminis (Plugins → DoneProject Plugin).
3. Lisa lehele/ postitusele shortcode (näide eespool).
+Testid
+
+Unit-testid kasutavad PHPUnitit ja WordPressi funktsioonide asendajaid (`tests/wp-stubs.php`), seega WordPressi installatsiooni pole vaja.
+
+1. `composer install`
+2. `composer test` (või `vendor/bin/phpunit`)
+3. Kaetuse aruanne: `php -d pcov.enabled=1 vendor/bin/phpunit --coverage-text` (nõuab pcov või Xdebug laiendust)
+
Piirangud ja tähelepanekud
- Pages ja category: vaikimisi ei kasuta WordPress pages taksonoomiat "category"; kui kasutad post_type="page" ja sinu lehed ei ole category-ga seotud, shortcode ei tagasta tulemusi — kasuta post tüüpi või registreeri category ka lehtedele.
diff --git a/composer.json b/composer.json
index 0834318..7f149d8 100644
--- a/composer.json
+++ b/composer.json
@@ -7,7 +7,19 @@
},
"autoload": {
"psr-4": {
- "DoneProject\\\\": "src/"
+ "DoneProject\\": "src/"
}
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "DoneProject\\Tests\\": "tests/"
+ }
+ },
+ "scripts": {
+ "test": "phpunit",
+ "test:coverage": "phpunit --coverage-text"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.6"
}
}
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
new file mode 100644
index 0000000..46a1497
--- /dev/null
+++ b/phpunit.xml.dist
@@ -0,0 +1,18 @@
+
+
+
+
+ tests
+
+
+
+
+ src
+
+
+
diff --git a/tests/AdminTest.php b/tests/AdminTest.php
new file mode 100644
index 0000000..627b034
--- /dev/null
+++ b/tests/AdminTest.php
@@ -0,0 +1,106 @@
+pluginStub() );
+
+ $hooks = array();
+ foreach ( WPStub::callsTo( 'add_action' ) as $call ) {
+ $hooks[ $call[0] ] = $call[1];
+ }
+
+ $this->assertSame( array( $admin, 'register_settings' ), $hooks['admin_init'] );
+ $this->assertSame( array( $admin, 'add_menu' ), $hooks['admin_menu'] );
+ }
+
+ public function testAddMenuRegistersOptionsPage(): void {
+ $admin = new Admin( $this->pluginStub() );
+
+ $admin->add_menu();
+
+ $this->assertSame(
+ array( 'DoneProject Settings', 'DoneProject', 'manage_options', 'doneproject-plugin', array( $admin, 'settings_page' ) ),
+ WPStub::firstCall( 'add_options_page' )
+ );
+ }
+
+ public function testRegisterSettingsRegistersOptionSectionAndField(): void {
+ $admin = new Admin( $this->pluginStub() );
+
+ $admin->register_settings();
+
+ $setting = WPStub::firstCall( 'register_setting' );
+ $this->assertSame( 'doneproject-plugin_group', $setting[0] );
+ $this->assertSame( 'doneproject-plugin_greeting', $setting[1] );
+ $this->assertSame(
+ array( 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field', 'default' => 'Tere' ),
+ $setting[2]
+ );
+
+ $section = WPStub::firstCall( 'add_settings_section' );
+ $this->assertSame( 'doneproject-plugin_section', $section[0] );
+ $this->assertSame( 'doneproject-plugin', $section[3] );
+
+ $field = WPStub::firstCall( 'add_settings_field' );
+ $this->assertSame( 'doneproject-plugin_greeting_field', $field[0] );
+ $this->assertSame( array( $admin, 'field_html' ), $field[2] );
+ $this->assertSame( 'doneproject-plugin', $field[3] );
+ $this->assertSame( 'doneproject-plugin_section', $field[4] );
+ }
+
+ public function testFieldHtmlRendersStoredValue(): void {
+ WPStub::$options['doneproject-plugin_greeting'] = 'Hei';
+ $admin = new Admin( $this->pluginStub() );
+
+ ob_start();
+ $admin->field_html();
+ $html = ob_get_clean();
+
+ $this->assertSame(
+ '',
+ $html
+ );
+ }
+
+ public function testFieldHtmlRendersDefaultAndEscapesValue(): void {
+ WPStub::$options['doneproject-plugin_greeting'] = 'Tere "sõber" & ';
+ $admin = new Admin( $this->pluginStub() );
+
+ ob_start();
+ $admin->field_html();
+ $html = ob_get_clean();
+
+ $this->assertStringContainsString( 'value="Tere "s', $html );
+ $this->assertStringNotContainsString( '', $html );
+ }
+
+ public function testSettingsPageRendersFormForPermittedUser(): void {
+ $admin = new Admin( $this->pluginStub() );
+
+ ob_start();
+ $admin->settings_page();
+ $html = ob_get_clean();
+
+ $this->assertStringContainsString( 'DoneProject seaded', $html );
+ $this->assertStringContainsString( '