diff --git a/modules/sms_devel/src/Form/SmsDevelMessageForm.php b/modules/sms_devel/src/Form/SmsDevelMessageForm.php index f29db10..9703e0b 100644 --- a/modules/sms_devel/src/Form/SmsDevelMessageForm.php +++ b/modules/sms_devel/src/Form/SmsDevelMessageForm.php @@ -64,6 +64,12 @@ public function getFormId() { * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state) { + $results = $form_state->getTemporaryValue('results'); + + if ($results) { + $form = array_merge($form, $this->verboseResults($results)); + } + $form['number'] = [ '#type' => 'tel', '#title' => $this->t('Phone number'), @@ -99,6 +105,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { '#title' => $this->t('Force skip queue'), '#description' => $this->t('Send or receive the message immediately. If the gateway-specific skip queue setting is turned on, then this option is already applied.'), '#default_value' => TRUE, + '#name' => 'skip_queue', ]; $form['options']['automated'] = [ '#type' => 'checkbox', @@ -106,6 +113,17 @@ public function buildForm(array $form, FormStateInterface $form_state) { '#description' => $this->t('Flag this message as automated.'), '#default_value' => TRUE, ]; + $form['options']['verbose'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Verbose output'), + '#description' => $this->t('Show full details of messages.'), + '#default_value' => TRUE, + '#states' => [ + 'visible' => [ + ':input[name="' . $form['options']['skip_queue']['#name'] . '"]' => ['checked' => TRUE], + ], + ], + ]; $form['options']['send_on'] = [ '#type' => 'datetime', '#title' => $this->t('Send on'), @@ -204,12 +222,18 @@ public function submitSend(array &$form, FormStateInterface $form_state) { $this->message->setDirection(Direction::OUTGOING); try { - if ($form_state->getValue('skip_queue')) { + $skip_queue = $form_state->getValue('skip_queue'); + $verbose = $form_state->getValue('verbose'); + if ($verbose && $skip_queue) { $messages = $this->smsProvider->send($this->message); + $results = []; foreach ($messages as $message) { $result = $message->getResult(); $this->resultMessage($result); + $results[] = $result; } + $form_state->setTemporaryValue('results', $results); + $form_state->setRebuild(); } else { $this->smsProvider->queue($this->message); @@ -252,4 +276,95 @@ protected function resultMessage(SmsMessageResultInterface $result) { } } + /** + * Render message results as a HTML table. + * + * @param \Drupal\sms\Message\SmsMessageResultInterface[] $results + * + * @return array + * A render array. + */ + protected function verboseResults(array $results) { + $render = []; + + // Renders plain text, or 'Undefined' message if falsey. + $renderString = function($value) { + return !empty($value) ? ['#plain_text' => $value] : ['#markup' => $this->t('Undefined')]; + }; + + // Renders a date text, or 'Undefined' message if falsey. + $renderDate = function($timestamp) { + if ($timestamp) { + $date = DrupalDateTime::createFromTimestamp($timestamp); + return ['#plain_text' => $date->format('c')]; + } + else { + return ['#markup' => $this->t('Undefined')]; + } + }; + + $render['results'] = [ + '#type' => 'table', + '#caption' => [ + 'heading' => [ + '#type' => 'inline_template', + '#template' => '

Results

', + ] + ], + '#header' => [ + $this->t('Result'), + $this->t('Error'), + $this->t('Error Message'), + $this->t('Credits Used'), + $this->t('Credits Balance'), + ], + ]; + + foreach ($results as $i => $result) { + $row = []; + $row[]['#plain_text'] = $this->t("#@number", ['@number' => $i]); + + $error = $result->getError(); + $row[] = $error ? ['#plain_text' => $error] : ['#markup' => $this->t('Success')]; + $row[] = $renderString($result->getErrorMessage()); + $row[] = $renderString($result->getCreditsUsed()); + $row[] = $renderString($result->getCreditsBalance()); + + $render['results'][] = $row; + + $reports_cell = [ + '#type' => 'table', + '#header' => [ + $this->t('Recipient'), + $this->t('Message ID'), + $this->t('Status'), + $this->t('Status Message'), + $this->t('Time Delivered'), + $this->t('Time Queued'), + ], + ]; + foreach ($result->getReports() as $report) { + $row = []; + + $row[] = $renderString($report->getRecipient()); + $row[] = $renderString($report->getMessageId()); + $row[] = $renderString($report->getStatus()); + $row[] = $renderString($report->getStatusMessage()); + $row[] = $renderDate($report->getTimeDelivered()); + $row[] = $renderDate($report->getTimeQueued()); + + $reports_cell[] = $row; + } + + $render['results'][][] = [ + '#wrapper_attributes' => [ + 'colspan' => count($render['results']['#header']), + ], + 'data' => $reports_cell, + ]; + } + + return $render; + } + } diff --git a/modules/sms_devel/tests/src/Functional/SmsDevelMessageTest.php b/modules/sms_devel/tests/src/Functional/SmsDevelMessageTest.php index f067278..036f43c 100644 --- a/modules/sms_devel/tests/src/Functional/SmsDevelMessageTest.php +++ b/modules/sms_devel/tests/src/Functional/SmsDevelMessageTest.php @@ -46,12 +46,12 @@ public function testSendSkipQueue() { $edit['skip_queue'] = TRUE; $this->drupalPostForm(Url::fromRoute('sms_devel.message'), $edit, t('Send')); - $this->assertResponse(200); - $this->assertRaw('Message was processed, 1 delivery reports were generated.'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->responseContains('Message was processed, 1 delivery reports were generated.'); $messages = $this->getTestMessages($this->gateway); - $this->assertEqual(1, count($messages)); - $this->assertEqual($edit['message'], $messages[0]->getMessage()); + $this->assertEquals(1, count($messages)); + $this->assertEquals($edit['message'], $messages[0]->getMessage()); } /** @@ -63,13 +63,13 @@ public function testSendNoSkipQueue() { $edit['skip_queue'] = FALSE; $this->drupalPostForm(Url::fromRoute('sms_devel.message'), $edit, t('Send')); - $this->assertResponse(200); - $this->assertRaw('Message added to the outgoing queue.'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->responseContains('Message added to the outgoing queue.'); $messages = SmsMessage::loadMultiple(); $message = reset($messages); - $this->assertEqual($edit['message'], $message->getMessage(), 'Message is same'); - $this->assertEqual(Direction::OUTGOING, $message->getDirection(), 'Message is outgoing'); + $this->assertEquals($edit['message'], $message->getMessage(), 'Message is same'); + $this->assertEquals(Direction::OUTGOING, $message->getDirection(), 'Message is outgoing'); } /** @@ -82,10 +82,10 @@ public function testReceiveSkipQueue() { $edit['skip_queue'] = TRUE; $this->drupalPostForm(Url::fromRoute('sms_devel.message'), $edit, t('Receive')); - $this->assertResponse(200); - $this->assertRaw('Message was processed, 1 delivery reports were generated.'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->responseContains('Message was processed, 1 delivery reports were generated.'); - $this->assertEqual($edit['message'], sms_test_gateway_get_incoming()['message']); + $this->assertEquals($edit['message'], sms_test_gateway_get_incoming()['message']); } /** @@ -98,13 +98,13 @@ public function testReceiveNoSkipQueue() { $edit['skip_queue'] = FALSE; $this->drupalPostForm(Url::fromRoute('sms_devel.message'), $edit, t('Receive')); - $this->assertResponse(200); - $this->assertRaw('Message added to the incoming queue.'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->responseContains('Message added to the incoming queue.'); $messages = SmsMessage::loadMultiple(); $message = reset($messages); - $this->assertEqual($edit['message'], $message->getMessage(), 'Message is same'); - $this->assertEqual(Direction::INCOMING, $message->getDirection(), 'Message is incoming'); + $this->assertEquals($edit['message'], $message->getMessage(), 'Message is same'); + $this->assertEquals(Direction::INCOMING, $message->getDirection(), 'Message is incoming'); } /** @@ -114,8 +114,8 @@ public function testReceiveGatewayInvalid() { $edit['gateway'] = ''; $this->drupalPostForm(Url::fromRoute('sms_devel.message'), $edit, t('Receive')); - $this->assertResponse(200); - $this->assertRaw('Gateway must be selected if receiving a message.'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->responseContains('Gateway must be selected if receiving a message.'); } /** @@ -128,7 +128,7 @@ public function testAutomated() { $edit['automated'] = FALSE; $this->drupalPostForm(Url::fromRoute('sms_devel.message'), $edit, t('Send')); - $this->assertResponse(200); + $this->assertSession()->statusCodeEquals(200); $messages = SmsMessage::loadMultiple(); $message = reset($messages); @@ -152,11 +152,11 @@ public function testDate() { $edit['send_on[date]'] = $date_user->format('Y-m-d'); $edit['send_on[time]'] = $date_user->format('H:i:s'); $this->drupalPostForm(Url::fromRoute('sms_devel.message'), $edit, t('Send')); - $this->assertResponse(200); + $this->assertSession()->statusCodeEquals(200); $messages = SmsMessage::loadMultiple(); $message = reset($messages); - $this->assertEqual($date->format('U'), $message->getSendTime(), 'Message has send time.'); + $this->assertEquals($date->format('U'), $message->getSendTime(), 'Message has send time.'); } /** @@ -170,11 +170,80 @@ public function testNoFallbackGateway() { $edit['skip_queue'] = TRUE; $this->drupalPostForm(Url::fromRoute('sms_devel.message'), $edit, t('Send')); - $this->assertResponse(200); - $this->assertRaw('Message could not be sent'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->responseContains('Message could not be sent'); $messages = $this->getTestMessages($this->gateway); - $this->assertEqual(0, count($messages), 'No messages sent.'); + $this->assertEquals(0, count($messages), 'No messages sent.'); + } + + /** + * Tests verbose message output. + */ + function testVerboseReports() { + $edit['gateway'] = $this->gateway->id(); + $edit['number'] = $this->randomPhoneNumbers(1)[0]; + $edit['message'] = $this->randomString(); + $edit['skip_queue'] = TRUE; + $edit['verbose'] = TRUE; + + $this->drupalPostForm(Url::fromRoute('sms_devel.message'), $edit, t('Send')); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->responseContains('Message was processed, 1 delivery reports were generated.'); + + $first_row = '#edit-results > tbody > tr:nth-child(1)'; + + // Result. + $selector = $first_row . ' > td:nth-child(1)'; + $this->assertSession()->elementTextContains('css', $selector, '#0'); + + // Error. + $selector = $first_row . ' > td:nth-child(2)'; + $this->assertSession()->elementTextContains('css', $selector, 'Success'); + + // Error Message. + $selector = $first_row . ' > td:nth-child(3)'; + $this->assertSession()->elementTextContains('css', $selector, 'Undefined'); + + // Credits Used. + $selector = $first_row . ' > td:nth-child(4)'; + $this->assertSession()->elementTextContains('css', $selector, 'Undefined'); + + // Credits Balance. + $selector = $first_row . ' > td:nth-child(5)'; + $this->assertSession()->elementTextContains('css', $selector, 'Undefined'); + + $message = $this->getLastTestMessage($this->gateway); + $report = $message->getReports()[0]; + $this->assertEquals($edit['number'], $report->getRecipient()); + + $first_row_first_report = '#edit-results > tbody > tr:nth-child(2) > td > table > tbody > tr:nth-child(1)'; + + // Recipient. + $selector = $first_row_first_report . ' > td:nth-child(1)'; + $this->assertSession()->elementTextContains('css', $selector, $report->getRecipient()); + + // Message ID. + $selector = $first_row_first_report . ' > td:nth-child(2)'; + $this->assertSession()->elementTextContains('css', $selector, $report->getMessageId()); + + // Status. + $selector = $first_row_first_report . ' > td:nth-child(3)'; + $this->assertSession()->elementTextContains('css', $selector, $report->getStatus()); + + // Status Message. + $selector = $first_row_first_report . ' > td:nth-child(4)'; + $this->assertSession()->elementTextContains('css', $selector, $report->getStatusMessage()); + + // Time Delivered. + $date = DrupalDateTime::createFromTimestamp($report->getTimeDelivered()); + $selector = $first_row_first_report . ' > td:nth-child(5)'; + $this->assertSession()->elementTextContains('css', $selector, $date->format('c')); + + // Time Queued. + $date = DrupalDateTime::createFromTimestamp($report->getTimeQueued()); + $selector = $first_row_first_report . ' > td:nth-child(6)'; + $this->assertSession()->elementTextContains('css', $selector, $date->format('c')); } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 7d0695a..97e4d4a 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -11,6 +11,7 @@ ./tests ./modules/sms_user/tests + ./modules/sms_devel/tests