Loading flag.routing.yml +22 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,17 @@ flag.action_link_flag: path: '/flag/flag/{flag}/{entity_id}' defaults: _controller: '\Drupal\flag\Controller\ActionLinkController::flag' methods: [POST] requirements: _flag_access: 'entity:flag{flag}' _format: 'html' _csrf_token: 'TRUE' flag.action_link_flag_nojs: path: '/flag/flag/{flag}/{entity_id}' defaults: _controller: '\Drupal\flag\Controller\ActionLinkNoJsController::flag' methods: [GET] requirements: _flag_access: 'entity:flag{flag}' _format: 'html' Loading @@ -51,6 +62,17 @@ flag.action_link_unflag: path: '/flag/unflag/{flag}/{entity_id}' defaults: _controller: '\Drupal\flag\Controller\ActionLinkController::unflag' methods: [POST] requirements: _unflag_access: 'entity:flag{flag}' _format: 'html' _csrf_token: 'TRUE' flag.action_link_unflag_nojs: path: '/flag/unflag/{flag}/{entity_id}' defaults: _controller: '\Drupal\flag\Controller\ActionLinkNoJsController::unflag' methods: [GET] requirements: _unflag_access: 'entity:flag{flag}' _format: 'html' Loading src/Controller/ActionLinkController.php +27 −58 Original line number Diff line number Diff line Loading @@ -6,28 +6,19 @@ use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Ajax\ReplaceCommand; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\EventSubscriber\MainContentViewSubscriber; use Drupal\Core\Render\RendererInterface; use Drupal\Core\Url; use Drupal\flag\Ajax\ActionLinkFlashCommand; use Drupal\flag\FlagInterface; use Drupal\flag\FlagServiceInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Drupal\Component\Utility\Html; /** * Controller responses to flag and unflag action links. * * If the action_link is a normal link then after an update the response to a * valid request is a redirect to the entity with drupal update message. * * For an ajax_action_link the response is a set of AJAX commands to update the * link in the page. If the user agent has javascript disabled then the * behaviour reverts to that of a normal link. * The response is a set of AJAX commands to update the * link in the page. */ class ActionLinkController implements ContainerInjectionInterface { /** * The flag service. Loading @@ -46,8 +37,10 @@ class ActionLinkController implements ContainerInjectionInterface { /** * Constructor. * * @param FlagServiceInterface $flag * @param \Drupal\flag\FlagServiceInterface $flag * The flag service. * @param \Drupal\Core\Render\RendererInterface $renderer * The renderer service. */ public function __construct(FlagServiceInterface $flag, RendererInterface $renderer) { $this->flagService = $flag; Loading @@ -71,15 +64,13 @@ class ActionLinkController implements ContainerInjectionInterface { * The flag entity. * @param int $entity_id * The flaggable entity ID. * @param \Symfony\Component\HttpFoundation\Request $request * The request. * * @return \Drupal\Core\Ajax\AjaxResponse|\Symfony\Component\HttpFoundation\RedirectResponse|null * @return \Drupal\Core\Ajax\AjaxResponse|null * The response object, only if successful. * * @see \Drupal\flag\Plugin\Reload */ public function flag(FlagInterface $flag, $entity_id, Request $request) { public function flag(FlagInterface $flag, $entity_id) { /* @var \Drupal\Core\Entity\EntityInterface $entity */ $entity = $this->flagService->getFlaggableById($flag, $entity_id); Loading @@ -91,7 +82,7 @@ class ActionLinkController implements ContainerInjectionInterface { // link for the existing state of the flag. } return $this->generateResponse($flag, $entity, $request, $flag->getMessage('flag')); return $this->generateResponse($flag, $entity, $flag->getMessage('flag')); } /** Loading @@ -101,15 +92,13 @@ class ActionLinkController implements ContainerInjectionInterface { * The flag entity. * @param int $entity_id * The flaggable entity ID. * @param \Symfony\Component\HttpFoundation\Request $request * The request. * * @return \Drupal\Core\Ajax\AjaxResponse|\Symfony\Component\HttpFoundation\RedirectResponse|null * @return \Drupal\Core\Ajax\AjaxResponse|null * The response object, only if successful. * * @see \Drupal\flag\Plugin\Reload */ public function unflag(FlagInterface $flag, $entity_id, Request $request) { public function unflag(FlagInterface $flag, $entity_id) { /* @var \Drupal\Core\Entity\EntityInterface $entity */ $entity = $this->flagService->getFlaggableById($flag, $entity_id); Loading @@ -121,7 +110,7 @@ class ActionLinkController implements ContainerInjectionInterface { // link for the existing state of the flag. } return $this->generateResponse($flag, $entity, $request, $flag->getMessage('unflag')); return $this->generateResponse($flag, $entity, $flag->getMessage('unflag')); } /** Loading @@ -134,11 +123,10 @@ class ActionLinkController implements ContainerInjectionInterface { * @param string $message * (optional) The message to flash. * * @return \Drupal\Core\Ajax\AjaxResponse|\Symfony\Component\HttpFoundation\RedirectResponse * @return \Drupal\Core\Ajax\AjaxResponse * The response object. */ protected function generateResponse(FlagInterface $flag, EntityInterface $entity, Request $request, $message = NULL) { if ($request->get(MainContentViewSubscriber::WRAPPER_FORMAT) == 'drupal_ajax') { private function generateResponse(FlagInterface $flag, EntityInterface $entity, $message) { // Create a new AJAX response. $response = new AjaxResponse(); Loading @@ -155,28 +143,9 @@ class ActionLinkController implements ContainerInjectionInterface { $replace = new ReplaceCommand($selector, $this->renderer->renderPlain($link)); $response->addCommand($replace); if ($message) { // Push a message pulsing command onto the stack. $pulse = new ActionLinkFlashCommand($selector, $message); $response->addCommand($pulse); } } elseif ($entity->hasLinkTemplate('canonical')) { // Redirect back to the entity. A passed in destination query parameter // will automatically override this. $url_info = $entity->toUrl(); $options['absolute'] = TRUE; $url = Url::fromRoute($url_info->getRouteName(), $url_info->getRouteParameters(), $options); $response = new RedirectResponse($url->toString()); } else { // For entities that don't have a canonical URL (like paragraphs), // redirect to the front page. $front = Url::fromUri('internal:/'); $response = new RedirectResponse($front); } return $response; } Loading src/Controller/ActionLinkNoJsController.php 0 → 100644 +150 −0 Original line number Diff line number Diff line <?php namespace Drupal\flag\Controller; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\Url; use Drupal\flag\FlagInterface; use Drupal\flag\FlagServiceInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; /** * Returns nojs responses to flag and unflag action links. * * "nojs" is when the user agent has javascript disabled the * behaviour reverts to that of a normal link. * * After an update the response to a valid request is a redirect to the entity * with drupal update message. */ class ActionLinkNoJsController implements ContainerInjectionInterface { /** * The flag service. * * @var \Drupal\flag\FlagServiceInterface */ protected $flagService; /** * The messenger service. * * @var \Drupal\Core\Messenger\MessengerInterface */ protected $messenger; /** * Constructor. * * @param \Drupal\flag\FlagServiceInterface $flag * The flag service. * @param \Drupal\Core\Messenger\MessengerInterface $messenger * The messenger service. */ public function __construct(FlagServiceInterface $flag, MessengerInterface $messenger) { $this->flagService = $flag; $this->messenger = $messenger; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { return new static( $container->get('flag'), $container->get('messenger') ); } /** * Performs a flagging when called via a route. * * @param \Drupal\flag\FlagInterface $flag * The flag entity. * @param int $entity_id * The flaggable entity ID. * * @return \Symfony\Component\HttpFoundation\RedirectResponse|null * The response object, only if successful. * * @see \Drupal\flag\Plugin\Reload */ public function flag(FlagInterface $flag, $entity_id) { /* @var \Drupal\Core\Entity\EntityInterface $entity */ $entity = $this->flagService->getFlaggableById($flag, $entity_id); try { $this->flagService->flag($flag, $entity); } catch (\LogicException $e) { // Fail silently so we return to the entity, which will show an updated // link for the existing state of the flag. } return $this->generateResponse($entity, $flag->getMessage('flag')); } /** * Performs a unflagging when called via a route. * * @param \Drupal\flag\FlagInterface $flag * The flag entity. * @param int $entity_id * The flaggable entity ID. * * @return \Symfony\Component\HttpFoundation\RedirectResponse|null * The response object, only if successful. * * @see \Drupal\flag\Plugin\Reload */ public function unflag(FlagInterface $flag, $entity_id) { /* @var \Drupal\Core\Entity\EntityInterface $entity */ $entity = $this->flagService->getFlaggableById($flag, $entity_id); try { $this->flagService->unflag($flag, $entity); } catch (\LogicException $e) { // Fail silently so we return to the entity, which will show an updated // link for the existing state of the flag. } return $this->generateResponse($entity, $flag->getMessage('unflag')); } /** * Generates a response after the flag has been updated. * * @param \Drupal\Core\Entity\EntityInterface $entity * The entity object. * @param string $message * The message to display. * * @return \Symfony\Component\HttpFoundation\RedirectResponse * The response object. */ private function generateResponse(EntityInterface $entity, $message) { $this->messenger->addMessage($message); if ($entity->hasLinkTemplate('canonical')) { // Redirect back to the entity. A passed in destination query parameter // will automatically override this. $url_info = $entity->toUrl(); $options['absolute'] = TRUE; $url = Url::fromRoute($url_info->getRouteName(), $url_info->getRouteParameters(), $options); $response = new RedirectResponse($url->toString()); } else { // For entities that don't have a canonical URL (like paragraphs), // redirect to the front page. $front = Url::fromUri('internal:/'); $response = new RedirectResponse($front); } return $response; } } tests/src/Functional/AjaxLinkNoJsTest.php 0 → 100644 +135 −0 Original line number Diff line number Diff line <?php namespace Drupal\Tests\flag\Functional; use Drupal\flag\Tests\FlagCreateTrait; use Drupal\Tests\BrowserTestBase; use Drupal\Tests\flag\Traits\FlagPermissionsTrait; use Drupal\Core\Url; /** * Test the NoJS responses to clicking on AjaxLinks. * * @see ActionLinkNoJsController * * @group flag */ class AjaxLinkNoJsTest extends BrowserTestBase { use FlagCreateTrait; use FlagPermissionsTrait; /** * {@inheritdoc} */ public static $modules = ['flag', 'node', 'user']; /** * Flag to test with. * * @var \Drupal\flag\FlagInterface */ protected $flag; /** * The flag service. * * @var \Drupal\flag\FlagServiceInterface */ protected $flagService; /** * Test node. * * @var \Drupal\node\NodeInterface */ protected $node; /** * Admin user. * * @var \Drupal\user\UserInterface */ protected $admin; /** * Normal user. * * @var \Drupal\user\UserInterface */ protected $webUser; /** * {@inheritdoc} */ protected function setUp() { parent::setUp(); // A article to test with. $this->createContentType(['type' => 'article']); $this->admin = $this->createUser(); $this->node = $this->createNode([ 'type' => 'article', 'uid' => $this->admin->id(), ]); // A test flag. $this->flag = $this->createFlag('node', ['article'], 'ajax_link'); $this->flagService = $this->container->get('flag'); $this->webUser = $this->createUser([ 'access content', ]); $this->grantFlagPermissions($this->flag); $this->drupalLogin($this->webUser); } /** * Test nojs response to AJAX links. * * The response is a redirect accompanied by a message appearing at the top * of the page. * * Click on flag and then unflag links verifying that the link cycles as * expected and flag message functions. */ public function testNoJsMessage() { // Get Page. $this->drupalGet(Url::fromRoute('entity.node.canonical', ['node' => $this->node->id()])); $session = $this->getSession(); // Verify initially flag link is on the page. $page = $session->getPage(); $flag_link = $page->findLink($this->flag->getShortText('flag')); $this->assertNotNull($flag_link, 'flag link exists.'); // Since this test is BrowserTestBase, and not JavascriptTestBase, this // simulates a noJS interaction. $flag_link->click(); // Verify flags message appears. $flag_message = $this->flag->getMessage('flag'); $this->assertSession()->pageTextContains($flag_message); // Verify new link. $unflag_link = $session->getPage()->findLink($this->flag->getShortText('unflag')); $this->assertNotNull($unflag_link, 'unflag link exists.'); // Simulate a noJs ActionLink (unflag). $unflag_link->click(); // Verfy unflag message appears. $unflag_message = $this->flag->getMessage('unflag'); $this->assertSession()->pageTextContains($unflag_message); // Verify the cycle completes and flag returns. $flag_link2 = $session->getPage()->findLink($this->flag->getShortText('flag')); $this->assertNotNull($flag_link2, 'flag cycle return to start.'); } } tests/src/FunctionalJavascript/AjaxLinkTest.php +2 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,8 @@ use Drupal\Tests\flag\Traits\FlagPermissionsTrait; * When a user clicks on an AJAX link a salvo of AJAX commands is issued in * response which update the DOM with a new link and a short lived message. * * @see ActionLinkController * * @group flag */ class AjaxLinkTest extends JavascriptTestBase { Loading Loading
flag.routing.yml +22 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,17 @@ flag.action_link_flag: path: '/flag/flag/{flag}/{entity_id}' defaults: _controller: '\Drupal\flag\Controller\ActionLinkController::flag' methods: [POST] requirements: _flag_access: 'entity:flag{flag}' _format: 'html' _csrf_token: 'TRUE' flag.action_link_flag_nojs: path: '/flag/flag/{flag}/{entity_id}' defaults: _controller: '\Drupal\flag\Controller\ActionLinkNoJsController::flag' methods: [GET] requirements: _flag_access: 'entity:flag{flag}' _format: 'html' Loading @@ -51,6 +62,17 @@ flag.action_link_unflag: path: '/flag/unflag/{flag}/{entity_id}' defaults: _controller: '\Drupal\flag\Controller\ActionLinkController::unflag' methods: [POST] requirements: _unflag_access: 'entity:flag{flag}' _format: 'html' _csrf_token: 'TRUE' flag.action_link_unflag_nojs: path: '/flag/unflag/{flag}/{entity_id}' defaults: _controller: '\Drupal\flag\Controller\ActionLinkNoJsController::unflag' methods: [GET] requirements: _unflag_access: 'entity:flag{flag}' _format: 'html' Loading
src/Controller/ActionLinkController.php +27 −58 Original line number Diff line number Diff line Loading @@ -6,28 +6,19 @@ use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Ajax\ReplaceCommand; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\EventSubscriber\MainContentViewSubscriber; use Drupal\Core\Render\RendererInterface; use Drupal\Core\Url; use Drupal\flag\Ajax\ActionLinkFlashCommand; use Drupal\flag\FlagInterface; use Drupal\flag\FlagServiceInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Drupal\Component\Utility\Html; /** * Controller responses to flag and unflag action links. * * If the action_link is a normal link then after an update the response to a * valid request is a redirect to the entity with drupal update message. * * For an ajax_action_link the response is a set of AJAX commands to update the * link in the page. If the user agent has javascript disabled then the * behaviour reverts to that of a normal link. * The response is a set of AJAX commands to update the * link in the page. */ class ActionLinkController implements ContainerInjectionInterface { /** * The flag service. Loading @@ -46,8 +37,10 @@ class ActionLinkController implements ContainerInjectionInterface { /** * Constructor. * * @param FlagServiceInterface $flag * @param \Drupal\flag\FlagServiceInterface $flag * The flag service. * @param \Drupal\Core\Render\RendererInterface $renderer * The renderer service. */ public function __construct(FlagServiceInterface $flag, RendererInterface $renderer) { $this->flagService = $flag; Loading @@ -71,15 +64,13 @@ class ActionLinkController implements ContainerInjectionInterface { * The flag entity. * @param int $entity_id * The flaggable entity ID. * @param \Symfony\Component\HttpFoundation\Request $request * The request. * * @return \Drupal\Core\Ajax\AjaxResponse|\Symfony\Component\HttpFoundation\RedirectResponse|null * @return \Drupal\Core\Ajax\AjaxResponse|null * The response object, only if successful. * * @see \Drupal\flag\Plugin\Reload */ public function flag(FlagInterface $flag, $entity_id, Request $request) { public function flag(FlagInterface $flag, $entity_id) { /* @var \Drupal\Core\Entity\EntityInterface $entity */ $entity = $this->flagService->getFlaggableById($flag, $entity_id); Loading @@ -91,7 +82,7 @@ class ActionLinkController implements ContainerInjectionInterface { // link for the existing state of the flag. } return $this->generateResponse($flag, $entity, $request, $flag->getMessage('flag')); return $this->generateResponse($flag, $entity, $flag->getMessage('flag')); } /** Loading @@ -101,15 +92,13 @@ class ActionLinkController implements ContainerInjectionInterface { * The flag entity. * @param int $entity_id * The flaggable entity ID. * @param \Symfony\Component\HttpFoundation\Request $request * The request. * * @return \Drupal\Core\Ajax\AjaxResponse|\Symfony\Component\HttpFoundation\RedirectResponse|null * @return \Drupal\Core\Ajax\AjaxResponse|null * The response object, only if successful. * * @see \Drupal\flag\Plugin\Reload */ public function unflag(FlagInterface $flag, $entity_id, Request $request) { public function unflag(FlagInterface $flag, $entity_id) { /* @var \Drupal\Core\Entity\EntityInterface $entity */ $entity = $this->flagService->getFlaggableById($flag, $entity_id); Loading @@ -121,7 +110,7 @@ class ActionLinkController implements ContainerInjectionInterface { // link for the existing state of the flag. } return $this->generateResponse($flag, $entity, $request, $flag->getMessage('unflag')); return $this->generateResponse($flag, $entity, $flag->getMessage('unflag')); } /** Loading @@ -134,11 +123,10 @@ class ActionLinkController implements ContainerInjectionInterface { * @param string $message * (optional) The message to flash. * * @return \Drupal\Core\Ajax\AjaxResponse|\Symfony\Component\HttpFoundation\RedirectResponse * @return \Drupal\Core\Ajax\AjaxResponse * The response object. */ protected function generateResponse(FlagInterface $flag, EntityInterface $entity, Request $request, $message = NULL) { if ($request->get(MainContentViewSubscriber::WRAPPER_FORMAT) == 'drupal_ajax') { private function generateResponse(FlagInterface $flag, EntityInterface $entity, $message) { // Create a new AJAX response. $response = new AjaxResponse(); Loading @@ -155,28 +143,9 @@ class ActionLinkController implements ContainerInjectionInterface { $replace = new ReplaceCommand($selector, $this->renderer->renderPlain($link)); $response->addCommand($replace); if ($message) { // Push a message pulsing command onto the stack. $pulse = new ActionLinkFlashCommand($selector, $message); $response->addCommand($pulse); } } elseif ($entity->hasLinkTemplate('canonical')) { // Redirect back to the entity. A passed in destination query parameter // will automatically override this. $url_info = $entity->toUrl(); $options['absolute'] = TRUE; $url = Url::fromRoute($url_info->getRouteName(), $url_info->getRouteParameters(), $options); $response = new RedirectResponse($url->toString()); } else { // For entities that don't have a canonical URL (like paragraphs), // redirect to the front page. $front = Url::fromUri('internal:/'); $response = new RedirectResponse($front); } return $response; } Loading
src/Controller/ActionLinkNoJsController.php 0 → 100644 +150 −0 Original line number Diff line number Diff line <?php namespace Drupal\flag\Controller; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\Url; use Drupal\flag\FlagInterface; use Drupal\flag\FlagServiceInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; /** * Returns nojs responses to flag and unflag action links. * * "nojs" is when the user agent has javascript disabled the * behaviour reverts to that of a normal link. * * After an update the response to a valid request is a redirect to the entity * with drupal update message. */ class ActionLinkNoJsController implements ContainerInjectionInterface { /** * The flag service. * * @var \Drupal\flag\FlagServiceInterface */ protected $flagService; /** * The messenger service. * * @var \Drupal\Core\Messenger\MessengerInterface */ protected $messenger; /** * Constructor. * * @param \Drupal\flag\FlagServiceInterface $flag * The flag service. * @param \Drupal\Core\Messenger\MessengerInterface $messenger * The messenger service. */ public function __construct(FlagServiceInterface $flag, MessengerInterface $messenger) { $this->flagService = $flag; $this->messenger = $messenger; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { return new static( $container->get('flag'), $container->get('messenger') ); } /** * Performs a flagging when called via a route. * * @param \Drupal\flag\FlagInterface $flag * The flag entity. * @param int $entity_id * The flaggable entity ID. * * @return \Symfony\Component\HttpFoundation\RedirectResponse|null * The response object, only if successful. * * @see \Drupal\flag\Plugin\Reload */ public function flag(FlagInterface $flag, $entity_id) { /* @var \Drupal\Core\Entity\EntityInterface $entity */ $entity = $this->flagService->getFlaggableById($flag, $entity_id); try { $this->flagService->flag($flag, $entity); } catch (\LogicException $e) { // Fail silently so we return to the entity, which will show an updated // link for the existing state of the flag. } return $this->generateResponse($entity, $flag->getMessage('flag')); } /** * Performs a unflagging when called via a route. * * @param \Drupal\flag\FlagInterface $flag * The flag entity. * @param int $entity_id * The flaggable entity ID. * * @return \Symfony\Component\HttpFoundation\RedirectResponse|null * The response object, only if successful. * * @see \Drupal\flag\Plugin\Reload */ public function unflag(FlagInterface $flag, $entity_id) { /* @var \Drupal\Core\Entity\EntityInterface $entity */ $entity = $this->flagService->getFlaggableById($flag, $entity_id); try { $this->flagService->unflag($flag, $entity); } catch (\LogicException $e) { // Fail silently so we return to the entity, which will show an updated // link for the existing state of the flag. } return $this->generateResponse($entity, $flag->getMessage('unflag')); } /** * Generates a response after the flag has been updated. * * @param \Drupal\Core\Entity\EntityInterface $entity * The entity object. * @param string $message * The message to display. * * @return \Symfony\Component\HttpFoundation\RedirectResponse * The response object. */ private function generateResponse(EntityInterface $entity, $message) { $this->messenger->addMessage($message); if ($entity->hasLinkTemplate('canonical')) { // Redirect back to the entity. A passed in destination query parameter // will automatically override this. $url_info = $entity->toUrl(); $options['absolute'] = TRUE; $url = Url::fromRoute($url_info->getRouteName(), $url_info->getRouteParameters(), $options); $response = new RedirectResponse($url->toString()); } else { // For entities that don't have a canonical URL (like paragraphs), // redirect to the front page. $front = Url::fromUri('internal:/'); $response = new RedirectResponse($front); } return $response; } }
tests/src/Functional/AjaxLinkNoJsTest.php 0 → 100644 +135 −0 Original line number Diff line number Diff line <?php namespace Drupal\Tests\flag\Functional; use Drupal\flag\Tests\FlagCreateTrait; use Drupal\Tests\BrowserTestBase; use Drupal\Tests\flag\Traits\FlagPermissionsTrait; use Drupal\Core\Url; /** * Test the NoJS responses to clicking on AjaxLinks. * * @see ActionLinkNoJsController * * @group flag */ class AjaxLinkNoJsTest extends BrowserTestBase { use FlagCreateTrait; use FlagPermissionsTrait; /** * {@inheritdoc} */ public static $modules = ['flag', 'node', 'user']; /** * Flag to test with. * * @var \Drupal\flag\FlagInterface */ protected $flag; /** * The flag service. * * @var \Drupal\flag\FlagServiceInterface */ protected $flagService; /** * Test node. * * @var \Drupal\node\NodeInterface */ protected $node; /** * Admin user. * * @var \Drupal\user\UserInterface */ protected $admin; /** * Normal user. * * @var \Drupal\user\UserInterface */ protected $webUser; /** * {@inheritdoc} */ protected function setUp() { parent::setUp(); // A article to test with. $this->createContentType(['type' => 'article']); $this->admin = $this->createUser(); $this->node = $this->createNode([ 'type' => 'article', 'uid' => $this->admin->id(), ]); // A test flag. $this->flag = $this->createFlag('node', ['article'], 'ajax_link'); $this->flagService = $this->container->get('flag'); $this->webUser = $this->createUser([ 'access content', ]); $this->grantFlagPermissions($this->flag); $this->drupalLogin($this->webUser); } /** * Test nojs response to AJAX links. * * The response is a redirect accompanied by a message appearing at the top * of the page. * * Click on flag and then unflag links verifying that the link cycles as * expected and flag message functions. */ public function testNoJsMessage() { // Get Page. $this->drupalGet(Url::fromRoute('entity.node.canonical', ['node' => $this->node->id()])); $session = $this->getSession(); // Verify initially flag link is on the page. $page = $session->getPage(); $flag_link = $page->findLink($this->flag->getShortText('flag')); $this->assertNotNull($flag_link, 'flag link exists.'); // Since this test is BrowserTestBase, and not JavascriptTestBase, this // simulates a noJS interaction. $flag_link->click(); // Verify flags message appears. $flag_message = $this->flag->getMessage('flag'); $this->assertSession()->pageTextContains($flag_message); // Verify new link. $unflag_link = $session->getPage()->findLink($this->flag->getShortText('unflag')); $this->assertNotNull($unflag_link, 'unflag link exists.'); // Simulate a noJs ActionLink (unflag). $unflag_link->click(); // Verfy unflag message appears. $unflag_message = $this->flag->getMessage('unflag'); $this->assertSession()->pageTextContains($unflag_message); // Verify the cycle completes and flag returns. $flag_link2 = $session->getPage()->findLink($this->flag->getShortText('flag')); $this->assertNotNull($flag_link2, 'flag cycle return to start.'); } }
tests/src/FunctionalJavascript/AjaxLinkTest.php +2 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,8 @@ use Drupal\Tests\flag\Traits\FlagPermissionsTrait; * When a user clicks on an AJAX link a salvo of AJAX commands is issued in * response which update the DOM with a new link and a short lived message. * * @see ActionLinkController * * @group flag */ class AjaxLinkTest extends JavascriptTestBase { Loading