public function ParagraphsAddWidgetTest::testModalAddWidgetDelta

Test Modal add widget with hidden delta field.

File

paragraphs/tests/src/FunctionalJavascript/ParagraphsAddWidgetTest.php, line 201

Class

ParagraphsAddWidgetTest
Test paragraphs user interface.

Namespace

Drupal\Tests\paragraphs\FunctionalJavascript

Code

public function testModalAddWidgetDelta() {
  $content_type = 'test_modal_delta';
  $this
    ->addParagraphedContentType($content_type);
  $this
    ->loginAsAdmin([
    "administer content types",
    "administer node form display",
    "edit any {$content_type} content",
    "create {$content_type} content",
  ]);

  // Set the add mode on the content type to modal form widget.
  $this
    ->drupalGet("admin/structure/types/manage/{$content_type}/form-display");
  $page = $this
    ->getSession()
    ->getPage();
  $page
    ->pressButton('field_paragraphs_settings_edit');
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();
  $edit = [
    'fields[field_paragraphs][settings_edit_form][settings][edit_mode]' => 'closed',
    'fields[field_paragraphs][settings_edit_form][settings][add_mode]' => 'modal',
  ];
  $this
    ->submitForm($edit, 'Update');
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();
  $this
    ->submitForm([], 'Save');

  // Add a Paragraph types.
  $this
    ->addParagraphsType('test_1');
  $this
    ->addParagraphsType('test_2');
  $this
    ->addParagraphsType('test_3');

  // Add a text field to the text_paragraph type.
  $this
    ->drupalGet('admin/structure/paragraphs_type/test_1/fields/add-field');
  if ($this
    ->coreVersion('10.2')) {
    $page
      ->selectFieldOption('new_storage_type', 'formatted_text');
    $this
      ->assertSession()
      ->waitForElementVisible('css', '#text_long');
    $page
      ->selectFieldOption('group_field_options_wrapper', 'text_long');
  }
  else {
    $page
      ->selectFieldOption('new_storage_type', 'text_long');
  }
  $page
    ->fillField('label', 'Text');
  $this
    ->assertSession()
    ->waitForElementVisible('css', '#edit-name-machine-name-suffix .link');
  $page
    ->pressButton('Edit');
  $page
    ->fillField('field_name', 'text_1');
  if ($this
    ->coreVersion('10.2')) {
    $page
      ->pressButton('Continue');
    $page
      ->pressButton('Save settings');
  }
  else {
    $page
      ->pressButton('Save and continue');
    $page
      ->pressButton('Save field settings');
    $page
      ->pressButton('Save settings');
  }
  $this
    ->drupalGet('admin/structure/paragraphs_type/test_2/fields/add-field');
  if ($this
    ->coreVersion('10.2')) {
    $page
      ->selectFieldOption('new_storage_type', 'formatted_text');
    $this
      ->assertSession()
      ->waitForElementVisible('css', '#text_long');
    $page
      ->selectFieldOption('group_field_options_wrapper', 'text_long');
  }
  else {
    $page
      ->selectFieldOption('new_storage_type', 'text_long');
  }
  $page
    ->fillField('label', 'Text');
  $this
    ->assertSession()
    ->waitForElementVisible('css', '#edit-name-machine-name-suffix .link');
  $page
    ->pressButton('Edit');
  $page
    ->fillField('field_name', 'text_2');
  if ($this
    ->coreVersion('10.2')) {
    $page
      ->pressButton('Continue');
    $page
      ->pressButton('Save settings');
  }
  else {
    $page
      ->pressButton('Save and continue');
    $page
      ->pressButton('Save field settings');
    $page
      ->pressButton('Save settings');
  }
  $this
    ->drupalGet('admin/structure/paragraphs_type/test_3/fields/add-field');
  if ($this
    ->coreVersion('10.2')) {
    $page
      ->selectFieldOption('new_storage_type', 'formatted_text');
    $this
      ->assertSession()
      ->waitForElementVisible('css', '#text_long');
    $page
      ->selectFieldOption('group_field_options_wrapper', 'text_long');
  }
  else {
    $page
      ->selectFieldOption('new_storage_type', 'text_long');
  }
  $page
    ->fillField('label', 'Text');
  $this
    ->assertSession()
    ->waitForElementVisible('css', '#edit-name-machine-name-suffix .link');
  $page
    ->pressButton('Edit');
  $page
    ->fillField('field_name', 'test_3');
  if ($this
    ->coreVersion('10.2')) {
    $page
      ->pressButton('Continue');
    $page
      ->pressButton('Save settings');
  }
  else {
    $page
      ->pressButton('Save and continue');
    $page
      ->pressButton('Save field settings');
    $page
      ->pressButton('Save settings');
  }

  // Create paragraph type Nested test.
  $this
    ->addParagraphsType('test_nested');
  $this
    ->drupalGet('/admin/structure/paragraphs_type/test_nested/fields/add-field');
  $page
    ->selectFieldOption('new_storage_type', 'field_ui:entity_reference_revisions:paragraph');
  $page
    ->fillField('label', 'Paragraphs');
  $this
    ->assertSession()
    ->waitForElementVisible('css', '#edit-name-machine-name-suffix .link');
  $page
    ->pressButton('Edit');
  $page
    ->fillField('field_name', 'paragraphs');
  if ($this
    ->coreVersion('10.2')) {
    $page
      ->pressButton('Continue');
    $page
      ->pressButton('Save settings');
  }
  else {
    $page
      ->pressButton('Save and continue');
    $page
      ->pressButton('Save field settings');
    $page
      ->pressButton('Save settings');
  }

  // Set the settings for the field in the nested paragraph.
  $component = [
    'type' => 'paragraphs',
    'region' => 'content',
    'settings' => [
      'edit_mode' => 'closed',
      'add_mode' => 'modal',
      'form_display_mode' => 'default',
    ],
  ];
  EntityFormDisplay::load('paragraph.test_nested.default')
    ->setComponent('field_paragraphs', $component)
    ->save();

  // Add a paragraphed test.
  $this
    ->drupalGet('node/add/test_modal_delta');
  $page
    ->fillField('title[0][value]', 'Test modal add widget delta');

  // Add a nested paragraph with the add widget - use negative delta.
  //
  // This case covers full execution of
  // ParagraphsWidget::prepareDeltaPosition() when list is empty.
  $this
    ->getSession()
    ->executeScript("jQuery('input.paragraph-type-add-delta').last().val(-100)");
  $page
    ->find('xpath', '//*[@name="button_add_modal"]')
    ->click();
  $page
    ->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_nested")]')
    ->click();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();

  // NOTE: After nested paragraphs is added there will be 2 add buttons and we
  // will use xpath "ancestor" axis to switch scope between base paragraphs
  // and nested paragraphs.
  //
  // For jQuery selector, we will use first() and last(), for nested and base
  // paragraph respectively.
  //
  // Add 2 additional paragraphs in base field.
  $this
    ->getSession()
    ->executeScript("jQuery('input.paragraph-type-add-delta').last().val('')");
  for ($i = 1; $i <= 2; $i++) {
    $page
      ->find('xpath', '//*[@name="button_add_modal" and not(ancestor::table)]')
      ->click();
    $this
      ->assertSession()
      ->assertWaitOnAjaxRequest();
    $page
      ->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_' . $i . '")]')
      ->click();
    $this
      ->assertSession()
      ->assertWaitOnAjaxRequest();
  }

  // There should be 3 paragraphs and last one should be "test_2" type.
  $base_paragraphs = $page
    ->findAll('xpath', '//*[contains(@class, "paragraph-type-label") and not(ancestor::div[contains(@class, "paragraphs-nested")])]');
  $this
    ->assertEquals(3, count($base_paragraphs), 'There should be 3 paragraphs.');
  $this
    ->assertEquals('test_2', $base_paragraphs[2]
    ->getText(), 'Last paragraph should be type "test_2".');

  // Add new paragraph to 1st position - set delta to 0 for base paragraphs.
  $this
    ->getSession()
    ->executeScript("jQuery('input.paragraph-type-add-delta').last().val(0)");
  $page
    ->find('xpath', '//*[@name="button_add_modal" and not(ancestor::table)]')
    ->click();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();
  $page
    ->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_3")]')
    ->click();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();

  // There should be 4 paragraphs and first one should be "test_3" type.
  $base_paragraphs = $page
    ->findAll('xpath', '//*[contains(@class, "paragraph-type-label") and not(ancestor::div[contains(@class, "paragraphs-nested")])]');
  $this
    ->assertEquals(4, count($base_paragraphs), 'There should be 4 paragraphs.');
  $this
    ->assertEquals('test_3', $base_paragraphs[0]
    ->getText(), '1st paragraph should be type "test_3".');

  // Add new paragraph to 3rd position - set delta to 2 for base paragraphs.
  $this
    ->getSession()
    ->executeScript("jQuery('input.paragraph-type-add-delta').last().val(2)");
  $page
    ->find('xpath', '//*[@name="button_add_modal" and not(ancestor::table)]')
    ->click();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();
  $page
    ->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_2")]')
    ->click();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();

  // There should be 5 paragraphs and 3rd one should be "test_2" type.
  $base_paragraphs = $page
    ->findAll('xpath', '//*[contains(@class, "paragraph-type-label") and not(ancestor::div[contains(@class, "paragraphs-nested")])]');
  $this
    ->assertEquals(5, count($base_paragraphs), 'There should be 5 paragraphs.');
  $this
    ->assertEquals('test_2', $base_paragraphs[2]
    ->getText(), '3rd paragraph should be type "test_2".');

  // Add new paragraph to last position - using really big delta.
  $this
    ->getSession()
    ->executeScript("jQuery('input.paragraph-type-add-delta').last().val(1000)");
  $page
    ->find('xpath', '//*[@name="button_add_modal" and not(ancestor::table)]')
    ->click();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();
  $page
    ->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_1")]')
    ->click();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();

  // There should be 6 paragraphs and last one should be "test_1" type.
  $base_paragraphs = $page
    ->findAll('xpath', '//*[contains(@class, "paragraph-type-label") and not(ancestor::div[contains(@class, "paragraphs-nested")])]');
  $this
    ->assertEquals(6, count($base_paragraphs), 'There should be 6 paragraphs.');
  $this
    ->assertEquals('test_1', $base_paragraphs[5]
    ->getText(), 'Last paragraph should be type "test_1".');

  // Clear delta base paragraphs.
  $this
    ->getSession()
    ->executeScript("jQuery('input.paragraph-type-add-delta').last().val('')");
  $page
    ->find('xpath', '//*[@name="button_add_modal" and not(ancestor::table)]')
    ->click();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();
  $page
    ->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_3")]')
    ->click();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();

  // There should be 7 paragraphs and last one should be "test_3" type.
  $base_paragraphs = $page
    ->findAll('xpath', '//*[contains(@class, "paragraph-type-label") and not(ancestor::div[contains(@class, "paragraphs-nested")])]');
  $this
    ->assertEquals(7, count($base_paragraphs), 'There should be 7 paragraphs.');
  $this
    ->assertEquals('test_3', $base_paragraphs[6]
    ->getText(), 'Last paragraph should be type "test_3".');

  // Save -> Open -> Check.
  $page
    ->pressButton('Save');
  $this
    ->drupalGet('/node/1/edit');

  // Check order for all Base Paragraphs.
  $base_paragraphs = $page
    ->findAll('xpath', '//*[contains(@class, "paragraph-type-label") and not(ancestor::div[contains(@class, "paragraphs-nested")])]');
  $base_paragraphs_type = [];
  foreach ($base_paragraphs as $base_paragraph) {
    $base_paragraphs_type[] = $base_paragraph
      ->getText();
  }
  $this
    ->assertEquals([
    'test_3',
    'test_nested',
    'test_2',
    'test_1',
    'test_2',
    'test_1',
    'test_3',
  ], $base_paragraphs_type);

  // Test adding in nested paragraphs.
  $page
    ->find('xpath', '//tr[2]/td[2]//*[contains(@class, "paragraphs-icon-button-edit")]')
    ->click();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();

  // Add paragraph in nested to have initial state for adding positions.
  $page
    ->find('xpath', '//*[@name="button_add_modal" and ancestor::table]')
    ->click();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();
  $page
    ->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_1")]')
    ->click();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();

  // Add new paragraph to first position.
  $this
    ->getSession()
    ->executeScript("jQuery('input.paragraph-type-add-delta').first().val(0)");
  $page
    ->find('xpath', '//*[@name="button_add_modal" and ancestor::table]')
    ->click();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();
  $page
    ->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_3")]')
    ->click();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();

  // Add new paragraph to 2nd position - using float value for index.
  $this
    ->getSession()
    ->executeScript("jQuery('input.paragraph-type-add-delta').first().val(1.1111)");
  $page
    ->find('xpath', '//*[@name="button_add_modal" and ancestor::table]')
    ->click();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();
  $page
    ->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_2")]')
    ->click();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();

  // Add new paragraph to first position - using negative index.
  $this
    ->getSession()
    ->executeScript("jQuery('input.paragraph-type-add-delta').first().val(-100)");
  $page
    ->find('xpath', '//*[@name="button_add_modal" and ancestor::table]')
    ->click();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();
  $page
    ->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_2")]')
    ->click();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();

  // Add new paragraph to last position - using some text as position.
  $this
    ->getSession()
    ->executeScript("jQuery('input.paragraph-type-add-delta').first().val('some_text')");
  $page
    ->find('xpath', '//*[@name="button_add_modal" and ancestor::table]')
    ->click();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();
  $page
    ->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_3")]')
    ->click();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();

  // Check order for all Nested Paragraphs.
  $nested_paragraphs = $page
    ->findAll('xpath', '//*[contains(@class, "paragraph-type-label") and ancestor::div[contains(@class, "paragraphs-nested")]]');
  $nested_paragraphs_type = [];
  foreach ($nested_paragraphs as $nested_paragraph) {
    $nested_paragraphs_type[] = $nested_paragraph
      ->getText();
  }
  $this
    ->assertEquals([
    'test_2',
    'test_3',
    'test_2',
    'test_1',
    'test_3',
  ], $nested_paragraphs_type);

  // Check the Add above functionality does not affect the position of the new
  // added Paragraphs when using the Add Paragraph button at the bottom.
  $this
    ->drupalGet('node/add/test_modal_delta');

  // Add a new Paragraph.
  $page
    ->find('xpath', '//*[@name="button_add_modal"]')
    ->click();
  $paragraphs_dialog = $this
    ->assertSession()
    ->waitForElementVisible('css', 'div.ui-dialog');
  $paragraphs_dialog
    ->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_1")]')
    ->press();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();

  // Attempt to add a new Paragraph above and cancel.
  $page
    ->find('xpath', '//*[@name="button_add_modal"]')
    ->click();
  $this
    ->getSession()
    ->executeScript("jQuery('input.paragraph-type-add-delta').first().val(0)");
  $this
    ->assertSession()
    ->elementExists('css', '.ui-dialog-titlebar-close')
    ->press();
  $delta = $this
    ->getSession()
    ->evaluateScript("jQuery('.paragraph-type-add-delta').val()");
  $this
    ->assertEquals($delta, '');

  // Add a new Paragraph with the Add button at the bottom.
  $page
    ->find('xpath', '//*[@name="button_add_modal"]')
    ->click();
  $paragraphs_dialog = $this
    ->assertSession()
    ->waitForElementVisible('css', 'div.ui-dialog');
  $paragraphs_dialog
    ->find('xpath', '//*[contains(@class, "paragraphs-add-dialog") and contains(@class, "ui-dialog-content")]//*[contains(@name, "test_2")]')
    ->press();
  $this
    ->assertSession()
    ->assertWaitOnAjaxRequest();

  // The position of it should be below the first added Paragraph.
  $base_paragraphs = $page
    ->findAll('xpath', '//*[contains(@class, "paragraph-type-label") and not(ancestor::div[contains(@class, "paragraphs-nested")])]');
  $base_paragraphs_type = [];
  foreach ($base_paragraphs as $base_paragraph) {
    $base_paragraphs_type[] = $base_paragraph
      ->getText();
  }
  $this
    ->assertEquals([
    'test_1',
    'test_2',
  ], $base_paragraphs_type);
}