304 lines
11 KiB
PHP
Executable File
304 lines
11 KiB
PHP
Executable File
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Modules\Helpdesk\Tests\Browser;
|
|
|
|
use Laravel\Dusk\Browser;
|
|
use Modules\Helpdesk\Models\Attachment;
|
|
use Modules\Helpdesk\Models\Ticket;
|
|
use Modules\Helpdesk\Tests\Concerns\BuildsHelpdeskFixtures;
|
|
use Tests\DuskTestCase;
|
|
|
|
final class HelpdeskCreateTicketAttachmentBrowserTest extends DuskTestCase
|
|
{
|
|
use BuildsHelpdeskFixtures;
|
|
|
|
public function test_user_can_create_ticket_with_attachment_in_browser(): void
|
|
{
|
|
$fixtures = $this->seedLookupData();
|
|
$user = $this->user(['name' => 'Browser Attachment User']);
|
|
$subject = 'Browser attachment ticket ' . uniqid('', true);
|
|
$filePath = $this->makeBrowserUploadFile('browser-upload-proof.log', 'Browser upload proof file.');
|
|
|
|
$this->browse(function (Browser $browser) use ($user, $fixtures, $subject, $filePath): void {
|
|
$browser->loginAs($user)
|
|
->visitRoute('helpdesk.tickets.create')
|
|
->waitFor('@helpdesk-ticket-create', 10)
|
|
->assertSee('Create ticket')
|
|
->type('@ticket-subject', $subject);
|
|
|
|
$browser->attach('#attachments', $filePath);
|
|
|
|
$this->waitForHelpdeskUploadToFinish($browser);
|
|
|
|
$browser->type('@ticket-subject', $subject);
|
|
$this->setHelpdeskSelect($browser, 'board_id', $fixtures['board']->id);
|
|
$this->setHelpdeskSelect($browser, 'priority_id', $fixtures['high']->id);
|
|
$this->setHelpdeskSelect($browser, 'category_id', $fixtures['category']->id);
|
|
$this->setHelpdeskSelect($browser, 'team_id', $fixtures['team']->id);
|
|
$this->setHelpdeskSelect($browser, 'project_id', $fixtures['project']->id);
|
|
$this->setHelpdeskEditor(
|
|
$browser,
|
|
'ticket-body-editor',
|
|
'This browser ticket proves attachments can be uploaded and saved.',
|
|
);
|
|
|
|
$this->submitTicketCreateComponent($browser);
|
|
|
|
$this->waitForTicketCreated($browser, $subject);
|
|
|
|
$browser->visitRoute('helpdesk.tickets.index')
|
|
->waitForText($subject, 10)
|
|
->assertPathIs('/helpdesk/tickets')
|
|
->assertSee($subject);
|
|
});
|
|
|
|
$ticket = Ticket::query()
|
|
->where('subject', $subject)
|
|
->firstOrFail();
|
|
|
|
$attachment = Attachment::query()
|
|
->where('ticket_id', $ticket->id)
|
|
->whereNull('comment_id')
|
|
->where('original_name', 'browser-upload-proof.log')
|
|
->firstOrFail();
|
|
|
|
self::assertSame($ticket->id, (int) $attachment->ticket_id);
|
|
}
|
|
|
|
public function test_user_can_create_ticket_with_multiple_attachments_in_browser(): void
|
|
{
|
|
$fixtures = $this->seedLookupData();
|
|
$user = $this->user(['name' => 'Browser Multi Attachment User']);
|
|
$subject = 'Browser multiple attachment ticket ' . uniqid('', true);
|
|
$firstFile = $this->makeBrowserUploadFile('browser-first-proof.txt', 'First browser upload proof file.');
|
|
$secondFile = $this->makeBrowserUploadFile('browser-second-proof.csv', 'name,value' . PHP_EOL . 'proof,1');
|
|
|
|
$this->browse(function (Browser $browser) use ($user, $fixtures, $subject, $firstFile, $secondFile): void {
|
|
$browser->loginAs($user)
|
|
->visitRoute('helpdesk.tickets.create')
|
|
->waitFor('@helpdesk-ticket-create', 10)
|
|
->assertSee('Create ticket')
|
|
->type('@ticket-subject', $subject);
|
|
|
|
$browser->attach('#attachments', $firstFile . "\n" . $secondFile);
|
|
|
|
$this->waitForHelpdeskUploadToFinish($browser);
|
|
|
|
$browser->type('@ticket-subject', $subject);
|
|
$this->setHelpdeskSelect($browser, 'board_id', $fixtures['board']->id);
|
|
$this->setHelpdeskSelect($browser, 'priority_id', $fixtures['normal']->id);
|
|
$this->setHelpdeskSelect($browser, 'category_id', $fixtures['category']->id);
|
|
$this->setHelpdeskSelect($browser, 'team_id', $fixtures['team']->id);
|
|
$this->setHelpdeskSelect($browser, 'project_id', $fixtures['project']->id);
|
|
$this->setHelpdeskEditor(
|
|
$browser,
|
|
'ticket-body-editor',
|
|
'This browser ticket proves multiple attachments can be uploaded and saved.',
|
|
);
|
|
|
|
$this->submitTicketCreateComponent($browser);
|
|
|
|
$this->waitForTicketCreated($browser, $subject);
|
|
|
|
$browser->visitRoute('helpdesk.tickets.index')
|
|
->waitForText($subject, 10)
|
|
->assertPathIs('/helpdesk/tickets')
|
|
->assertSee($subject);
|
|
});
|
|
|
|
$ticket = Ticket::query()
|
|
->where('subject', $subject)
|
|
->firstOrFail();
|
|
|
|
self::assertSame(
|
|
2,
|
|
Attachment::query()->where('ticket_id', $ticket->id)->whereNull('comment_id')->count(),
|
|
);
|
|
|
|
foreach (['browser-first-proof.txt', 'browser-second-proof.csv'] as $name) {
|
|
$this->assertDatabaseHas('helpdesk_attachments', [
|
|
'ticket_id' => $ticket->id,
|
|
'comment_id' => null,
|
|
'original_name' => $name,
|
|
]);
|
|
}
|
|
}
|
|
|
|
private function makeBrowserUploadFile(string $name, string $contents): string
|
|
{
|
|
$directory = storage_path('framework/testing/helpdesk-browser-uploads');
|
|
|
|
if (! is_dir($directory)) {
|
|
mkdir($directory, 0777, true);
|
|
}
|
|
|
|
$path = $directory . DIRECTORY_SEPARATOR . $name;
|
|
file_put_contents($path, $contents);
|
|
|
|
return $path;
|
|
}
|
|
|
|
private function setHelpdeskEditor(Browser $browser, string $dusk, string $text): void
|
|
{
|
|
$encodedDusk = json_encode($dusk, JSON_THROW_ON_ERROR);
|
|
$encodedText = json_encode($text, JSON_THROW_ON_ERROR);
|
|
|
|
$browser->script(<<<JS
|
|
const key = {$encodedDusk};
|
|
const text = {$encodedText};
|
|
const root = document.querySelector('[dusk="' + key + '"], [data-dusk="' + key + '"]');
|
|
|
|
if (! root) {
|
|
throw new Error('Helpdesk editor ' + key + ' was not found.');
|
|
}
|
|
|
|
const editor = root.matches('textarea, input, [contenteditable="true"]')
|
|
? root
|
|
: root.querySelector('textarea, input, [contenteditable="true"]');
|
|
|
|
if (! editor) {
|
|
throw new Error('Helpdesk editor content area ' + key + ' was not found.');
|
|
}
|
|
|
|
editor.focus();
|
|
|
|
if (editor.matches('textarea, input')) {
|
|
editor.value = text;
|
|
} else {
|
|
editor.textContent = text;
|
|
}
|
|
|
|
editor.dispatchEvent(new InputEvent('input', {
|
|
bubbles: true,
|
|
composed: true,
|
|
inputType: 'insertText',
|
|
data: text,
|
|
}));
|
|
editor.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
|
|
editor.dispatchEvent(new Event('blur', { bubbles: true, composed: true }));
|
|
|
|
const model = root.getAttribute('wire:model')
|
|
|| root.getAttribute('wire:model.live')
|
|
|| root.getAttribute('wire:model.defer')
|
|
|| root.getAttribute('data-wire-model')
|
|
|| editor.getAttribute('data-wire-model')
|
|
|| editor.getAttribute('data-helpdesk-editor-model')
|
|
|| editor.getAttribute('data-helpdesk-sync-target');
|
|
|
|
let componentRoot = root;
|
|
while (componentRoot && ! componentRoot.hasAttribute('wire:id')) {
|
|
componentRoot = componentRoot.parentElement;
|
|
}
|
|
|
|
if (model && componentRoot && window.Livewire) {
|
|
const component = window.Livewire.find(componentRoot.getAttribute('wire:id'));
|
|
|
|
if (component) {
|
|
component.set(model, text);
|
|
}
|
|
}
|
|
JS);
|
|
|
|
$browser->pause(500);
|
|
}
|
|
|
|
private function setHelpdeskSelect(Browser $browser, string $model, int|string|null $value): void
|
|
{
|
|
$encodedModel = json_encode($model, JSON_THROW_ON_ERROR);
|
|
$encodedValue = json_encode($value === null ? '' : (string) $value, JSON_THROW_ON_ERROR);
|
|
|
|
$browser->script(<<<JS
|
|
const model = {$encodedModel};
|
|
const value = {$encodedValue};
|
|
const select = document.querySelector('[data-wire-model="' + model + '"]');
|
|
|
|
if (! select) {
|
|
throw new Error('Helpdesk select ' + model + ' was not found.');
|
|
}
|
|
|
|
select.value = value;
|
|
select.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
|
|
|
|
if (window.jQuery) {
|
|
window.jQuery(select).val(value).trigger('change.select2').trigger('change.helpdesk-select2').trigger('change');
|
|
}
|
|
|
|
let componentRoot = select;
|
|
while (componentRoot && ! componentRoot.hasAttribute('wire:id')) {
|
|
componentRoot = componentRoot.parentElement;
|
|
}
|
|
|
|
if (componentRoot && window.Livewire) {
|
|
const component = window.Livewire.find(componentRoot.getAttribute('wire:id'));
|
|
|
|
if (component) {
|
|
component.set(model, value === '' ? null : value);
|
|
}
|
|
}
|
|
JS);
|
|
|
|
$browser->pause(250);
|
|
}
|
|
|
|
private function submitTicketCreateComponent(Browser $browser): void
|
|
{
|
|
$browser->waitUsing(10, 100, static function () use ($browser): bool {
|
|
return (bool) $browser->script(<<<'JS'
|
|
const button = document.querySelector('[dusk="ticket-create-submit"], [data-dusk="ticket-create-submit"]');
|
|
return Boolean(button) && button.disabled === false;
|
|
JS)[0];
|
|
}, 'The helpdesk ticket create form was not ready to submit.');
|
|
|
|
$browser->script(<<<'JS'
|
|
const root = document.querySelector('[dusk="helpdesk-ticket-create"], [data-dusk="helpdesk-ticket-create"]');
|
|
|
|
if (! root) {
|
|
throw new Error('Helpdesk ticket create root was not found.');
|
|
}
|
|
|
|
let componentRoot = root;
|
|
while (componentRoot && ! componentRoot.hasAttribute('wire:id')) {
|
|
componentRoot = componentRoot.parentElement;
|
|
}
|
|
|
|
if (! componentRoot || ! window.Livewire) {
|
|
throw new Error('Helpdesk Livewire create component was not found.');
|
|
}
|
|
|
|
const component = window.Livewire.find(componentRoot.getAttribute('wire:id'));
|
|
|
|
if (! component) {
|
|
throw new Error('Helpdesk Livewire create component instance was not found.');
|
|
}
|
|
|
|
component.call('save');
|
|
JS);
|
|
}
|
|
|
|
private function waitForHelpdeskUploadToFinish(Browser $browser): void
|
|
{
|
|
$browser->waitUsing(30, 250, static function () use ($browser): bool {
|
|
return (bool) $browser->script(<<<'JS'
|
|
const input = document.querySelector('#attachments');
|
|
const button = document.querySelector('[dusk="ticket-create-submit"], [data-dusk="ticket-create-submit"]');
|
|
const selected = document.querySelector('[dusk="ticket-create-selected-attachments"], [data-dusk="ticket-create-selected-attachments"]');
|
|
|
|
return Boolean(input)
|
|
&& input.files.length > 0
|
|
&& Boolean(selected)
|
|
&& Boolean(button)
|
|
&& button.disabled === false;
|
|
JS)[0];
|
|
}, 'The Livewire temporary attachment upload did not finish before submit.');
|
|
}
|
|
|
|
private function waitForTicketCreated(Browser $browser, string $subject): void
|
|
{
|
|
$browser->waitUsing(20, 250, static fn (): bool => Ticket::query()
|
|
->where('subject', $subject)
|
|
->exists(), 'The browser did not create the helpdesk ticket before the timeout.');
|
|
}
|
|
}
|