trypost/tests/Feature/Permissions/WorkspaceRolePermissionsTest.php
Paulo Castellano d8149ef058
Remove the automations module (#333)
* Remove the automations module

Drops the visual workflow builder end to end: actions, node runners,
commands, jobs, models, observers, policy, resources, requests, routes,
broadcast channel, scheduler entries, Horizon supervisor, Vue pages and
components, canvas undo/redo history, CodeEditor, translations, factories
and tests.

A new migration rewrites posts.created_via = 'automation' to 'web' and
drops the five automation tables. The CreatedVia::Automation enum case is
removed. The 2026-08-21 social-account identity migration now skips its
automation node repointing when the automations table no longer exists,
so it stays re-runnable after the drop.

Orphaned dependencies removed: simplepie/simplepie, @vue-flow/*,
codemirror and @codemirror/*.

* Drop the orphaned common.beta translation key

* Remove automation leftovers: ResolvableUrl rule, feed fixtures, useShortcut, nav badge

* Drop the unused chart wrapper and @unovis packages

* Address review: keep the shipped migration untouched, drop the dead previewOnly chain

- Restore 2026_08_21 migration to exactly what production ran; the
  rehearsal test now recreates the automations table it expects instead.
- Mark the drop migration's down() irreversible like its siblings.
- Simplify DropAutomationTablesMigrationTest to the sibling shape.
- Remove previewOnly / aiGenerateVariants: the only caller that set the
  prop was the deleted automation Generate node.
- Run pint over lang/*/common.php after the beta key removal.

* Exercise the drop migration against the real automation tables and their FKs

* Drop DuplicateIdentityRehearsalTest: it re-ran a frozen migration that reads the removed automations table
2026-09-05 11:03:23 -03:00

150 lines
5 KiB
PHP

<?php
declare(strict_types=1);
use App\Enums\Post\Status;
use App\Enums\UserWorkspace\Role;
use App\Models\Post;
use App\Models\SocialAccount;
use App\Models\User;
use App\Models\Workspace;
beforeEach(function () {
$this->owner = User::factory()->create();
$this->workspace = Workspace::factory()->create([
'account_id' => $this->owner->account_id,
'user_id' => $this->owner->id,
]);
$this->owner->update(['current_workspace_id' => $this->workspace->id]);
$this->viewer = User::factory()->create([
'account_id' => $this->owner->account_id,
'current_workspace_id' => $this->workspace->id,
]);
$this->workspace->members()->attach($this->viewer->id, ['role' => Role::Viewer->value]);
$this->member = User::factory()->create([
'account_id' => $this->owner->account_id,
'current_workspace_id' => $this->workspace->id,
]);
$this->workspace->members()->attach($this->member->id, ['role' => Role::Member->value]);
$this->admin = User::factory()->create([
'account_id' => $this->owner->account_id,
'current_workspace_id' => $this->workspace->id,
]);
$this->workspace->members()->attach($this->admin->id, ['role' => Role::Admin->value]);
$this->post = Post::factory()->create(['workspace_id' => $this->workspace->id]);
});
test('a viewer cannot delete a post', function () {
$this->actingAs($this->viewer)
->delete(route('app.posts.destroy', $this->post))
->assertForbidden();
$this->assertDatabaseHas('posts', ['id' => $this->post->id]);
});
test('a viewer can comment on a post', function () {
$this->actingAs($this->viewer)
->postJson(route('app.posts.comments.store', $this->post), ['body' => 'Looks good!'])
->assertSuccessful();
$this->assertDatabaseHas('post_comments', [
'post_id' => $this->post->id,
'user_id' => $this->viewer->id,
]);
});
test('opening a draft post redirects to the editor for every workspace member', function (string $actor) {
$this->actingAs($this->{$actor})
->get(route('app.posts.show', $this->post))
->assertRedirect(route('app.posts.edit', $this->post));
})->with(['admin', 'member', 'viewer']);
test('a viewer can open the post editor to review and comment', function () {
$this->actingAs($this->viewer)
->get(route('app.posts.edit', $this->post))
->assertOk();
});
test('a viewer cannot save changes to a post', function () {
$this->actingAs($this->viewer)
->put(route('app.posts.update', $this->post), ['status' => Status::Draft->value])
->assertForbidden();
});
test('only admins and above can open the connections screen', function (string $actor, bool $allowed) {
$response = $this->actingAs($this->{$actor})->get(route('app.accounts'));
$allowed ? $response->assertOk() : $response->assertForbidden();
})->with([
'admin' => ['admin', true],
'member' => ['member', false],
'viewer' => ['viewer', false],
]);
test('opening the editor does not create platform rows for a viewer', function () {
SocialAccount::factory()->create([
'workspace_id' => $this->workspace->id,
'is_active' => true,
]);
$this->actingAs($this->viewer)
->get(route('app.posts.edit', $this->post))
->assertOk();
expect($this->post->postPlatforms()->count())->toBe(0);
});
test('opening the editor syncs platform rows for a member', function () {
SocialAccount::factory()->create([
'workspace_id' => $this->workspace->id,
'is_active' => true,
]);
$this->actingAs($this->member)
->get(route('app.posts.edit', $this->post))
->assertOk();
expect($this->post->postPlatforms()->count())->toBe(1);
});
test('a member without connected accounts is redirected away from the admin-only accounts screen when creating a post', function () {
$this->actingAs($this->member)
->post(route('app.posts.store'))
->assertRedirect(route('app.calendar'));
});
test('an admin without connected accounts is sent to the accounts screen when creating a post', function () {
$this->actingAs($this->admin)
->post(route('app.posts.store'))
->assertRedirect(route('app.accounts'));
});
test('a member cannot open the create workspace form', function () {
$this->actingAs($this->member)
->get(route('app.workspaces.create'))
->assertForbidden();
});
test('a member cannot store a workspace on the shared account', function () {
$this->actingAs($this->member)
->post(route('app.workspaces.store'), [
'name' => 'Sneaky Workspace',
])
->assertForbidden();
expect(Workspace::where('name', 'Sneaky Workspace')->exists())->toBeFalse();
});
test('a workspace admin cannot store a workspace on the shared account', function () {
$this->actingAs($this->admin)
->post(route('app.workspaces.store'), [
'name' => 'Admin Workspace',
])
->assertForbidden();
expect(Workspace::where('name', 'Admin Workspace')->exists())->toBeFalse();
});