Skip to content

Commit 69c3f0b

Browse files
committed
test(functional/activation): add functional and unit test coverage
Add functional tests for database activation lifecycle and table storage behavior. Extend unit tests for `ActivationExecute` and `ActivationTasks` to ensure proper task registration and lifecycle execution. Update `yarn.lock` to use npm registry consistently.
1 parent e412575 commit 69c3f0b

7 files changed

Lines changed: 2872 additions & 2424 deletions

File tree

‎phpunit.xml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
<exclude>
2525
<directory>./sources/**/**/build-module</directory>
2626
<directory>./sources/**/**/dist</directory>
27+
<file>./sources/Blocks/blocks-manifest.php</file>
2728
</exclude>
2829
</source>
2930

‎tests/functional/php/Blocks/BlockHooksTest.php‎

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace SpaghettiDojo\Konomi\Tests\Functional\Blocks;
66

7+
use SpaghettiDojo\Konomi\Blocks\Konomi\HookedContent;
8+
79
// Block Hooks auto-insertion of `konomi/konomi` after `core/post-title`. The hooked
810
// instance is inserted bare by WordPress; the `hooked_block_konomi/konomi` filter
911
// (SpaghettiDojo\Konomi\Blocks\Konomi\HookedContent) must populate it with the default
@@ -47,7 +49,7 @@
4749
});
4850

4951
it('does not override a block that already has inner blocks', function (): void {
50-
$hookedContent = \SpaghettiDojo\Konomi\Blocks\Konomi\HookedContent::new();
52+
$hookedContent = HookedContent::new();
5153

5254
$alreadyPopulated = [
5355
'blockName' => 'konomi/konomi',
@@ -69,4 +71,19 @@
6971

7072
expect($result)->toBe($alreadyPopulated);
7173
});
74+
75+
it('leaves a suppressed (non-array) hooked block untouched', function (): void {
76+
$hookedContent = HookedContent::new();
77+
78+
// A prior filter may have returned null to suppress the insertion.
79+
$result = $hookedContent->injectDefaultInnerBlocks(
80+
null,
81+
'konomi/konomi',
82+
'after',
83+
null,
84+
null
85+
);
86+
87+
expect($result)->toBeNull();
88+
});
7289
});
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SpaghettiDojo\Konomi\Tests\Functional\Database;
6+
7+
use SpaghettiDojo\Konomi\Activation\ActivationTasks;
8+
use SpaghettiDojo\Konomi\Database\InteractionsTable;
9+
use SpaghettiDojo\Konomi\Database\Module;
10+
11+
use function SpaghettiDojo\Konomi\package;
12+
13+
function tableExists(string $name): bool
14+
{
15+
global $wpdb;
16+
17+
$wpdb->suppress_errors(true);
18+
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
19+
$result = $wpdb->query("SELECT 1 FROM {$name} LIMIT 1");
20+
$wpdb->suppress_errors(false);
21+
22+
return $result !== false;
23+
}
24+
25+
describe('Database\Module::services()', function (): void {
26+
it('exposes the InteractionsTable named from the wpdb prefix', function (): void {
27+
global $wpdb;
28+
$table = package()->container()->get(InteractionsTable::class);
29+
expect($table->name())->toBe($wpdb->prefix . 'konomi_interactions');
30+
});
31+
});
32+
33+
describe('Database\Module::activate()', function (): void {
34+
it('registers activation/uninstall tasks that create and drop the real table', function (): void {
35+
$container = package()->container();
36+
$table = $container->get(InteractionsTable::class);
37+
$tasks = $container->get(ActivationTasks::class);
38+
39+
Module::new()->activate($tasks, $container);
40+
41+
expect($tasks->activationTasks())->toHaveCount(1)
42+
->and($tasks->uninstallTasks())->toHaveCount(1)
43+
->and($tasks->deactivationTasks())->toBe([]);
44+
45+
// The table already exists (created in WpTestCase::setUp). The uninstall
46+
// task drops it, the activation task recreates it (idempotent via dbDelta).
47+
($tasks->uninstallTasks()[0])();
48+
expect(tableExists($table->name()))->toBeFalse();
49+
50+
($tasks->activationTasks()[0])();
51+
expect(tableExists($table->name()))->toBeTrue();
52+
});
53+
});
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SpaghettiDojo\Konomi\Tests\Functional\Storage;
6+
7+
use SpaghettiDojo\Konomi\Database\InteractionsTable;
8+
use SpaghettiDojo\Konomi\Storage\Axis;
9+
use SpaghettiDojo\Konomi\Storage\Record;
10+
use SpaghettiDojo\Konomi\Storage\TableStorage;
11+
12+
beforeEach(function (): void {
13+
global $wpdb;
14+
$this->table = InteractionsTable::new($wpdb->prefix);
15+
$this->storage = TableStorage::new($this->table);
16+
});
17+
18+
describe('TableStorage round trip', function (): void {
19+
it('writes and reads records on the Entity axis', function (): void {
20+
$ok = $this->storage->write(Axis::Entity, 10, 'reaction', [
21+
new Record(0, 5, 'post'),
22+
new Record(0, 7, 'post'),
23+
]);
24+
expect($ok)->toBeTrue();
25+
26+
$records = $this->storage->read(Axis::Entity, 10, 'reaction');
27+
$userIds = array_map(static fn (Record $record) => $record->userId, $records);
28+
sort($userIds);
29+
30+
expect($records)->toHaveCount(2)
31+
->and($userIds)->toBe([5, 7])
32+
->and($records[0]->entityId)->toBe(10)
33+
->and($records[0]->entityType)->toBe('post');
34+
});
35+
36+
it('writes and reads records on the User axis', function (): void {
37+
$ok = $this->storage->write(Axis::User, 99, 'bookmark', [
38+
new Record(3, 0, 'post'),
39+
new Record(4, 0, 'page'),
40+
]);
41+
expect($ok)->toBeTrue();
42+
43+
$records = $this->storage->read(Axis::User, 99, 'bookmark');
44+
$entityIds = array_map(static fn (Record $record) => $record->entityId, $records);
45+
sort($entityIds);
46+
47+
expect($records)->toHaveCount(2)
48+
->and($entityIds)->toBe([3, 4])
49+
->and($records[0]->userId)->toBe(99);
50+
});
51+
52+
it('replaces the previous set for the same axis id and group on write', function (): void {
53+
$this->storage->write(Axis::Entity, 10, 'reaction', [new Record(0, 5, 'post')]);
54+
$this->storage->write(Axis::Entity, 10, 'reaction', [new Record(0, 8, 'post')]);
55+
56+
$records = $this->storage->read(Axis::Entity, 10, 'reaction');
57+
58+
expect($records)->toHaveCount(1)
59+
->and($records[0]->userId)->toBe(8);
60+
});
61+
62+
it('keeps different group keys isolated', function (): void {
63+
$this->storage->write(Axis::Entity, 10, 'reaction', [new Record(0, 5, 'post')]);
64+
65+
expect($this->storage->read(Axis::Entity, 10, 'bookmark'))->toBe([]);
66+
});
67+
68+
it('filters out malformed rows on read', function (): void {
69+
global $wpdb;
70+
71+
$this->storage->write(Axis::Entity, 10, 'reaction', [new Record(0, 5, 'post')]);
72+
73+
// A row with an empty entity_type must be dropped by TableStorage::mapRow().
74+
$wpdb->insert(
75+
$this->table->name(),
76+
['entity_id' => 10, 'user_id' => 6, 'entity_type' => '', 'group_key' => 'reaction'],
77+
['%d', '%d', '%s', '%s']
78+
);
79+
80+
$records = $this->storage->read(Axis::Entity, 10, 'reaction');
81+
82+
expect($records)->toHaveCount(1)
83+
->and($records[0]->userId)->toBe(5);
84+
});
85+
});

0 commit comments

Comments
 (0)