You are here

public function LocalTranslatorTest::testBasicWorkflow in Translation Management Tool 8

Test the basic translation workflow.

File

translators/tmgmt_local/tests/src/Functional/LocalTranslatorTest.php, line 150

Class

LocalTranslatorTest
Basic tests for the local translator.

Namespace

Drupal\Tests\tmgmt_local\Functional

Code

public function testBasicWorkflow() {
  $translator = Translator::load('local');

  /** @var FilterFormat $basic_html_format */
  $basic_html_format = FilterFormat::create(array(
    'format' => 'basic_html',
    'name' => 'Basic HTML',
  ));
  $basic_html_format
    ->save();

  // Create a job and request a local translation.
  $this
    ->loginAsTranslator();
  $job = $this
    ->createJob();
  $job->translator = $translator
    ->id();
  $job
    ->addItem('test_source', 'test', '1');
  \Drupal::state()
    ->set('tmgmt.test_source_data', [
    'dummy' => [
      'deep_nesting' => [
        '#text' => file_get_contents(drupal_get_path('module', 'tmgmt') . '/tests/testing_html/sample.html'),
        '#label' => 'Label for job item with type test and id 2.',
        '#translate' => TRUE,
        '#format' => 'basic_html',
      ],
    ],
    'second' => [
      '#text' => 'second text',
      '#label' => 'Second label',
      '#translate' => TRUE,
    ],
    'third' => [
      '#text' => 'third text',
      '#label' => 'Third label',
      '#translate' => TRUE,
    ],
  ]);
  $job
    ->addItem('test_source', 'test', '2');
  $job
    ->save();

  // Make sure that the checkout page works as expected when there are no
  // roles.
  $this
    ->drupalGet($job
    ->toUrl());
  $this
    ->assertText(t('@translator can not translate from @source to @target.', array(
    '@translator' => 'Drupal user',
    '@source' => 'English',
    '@target' => 'German',
  )));
  $element = $this
    ->xpath('//*[@id="edit-translator"]/option')[0];
  $this
    ->assertEqual($element
    ->getText(), 'Drupal user (unsupported)');
  $this->assignee = $this
    ->drupalCreateUser(array_merge($this->localTranslatorPermissions, [
    $basic_html_format
      ->getPermissionName(),
  ]));

  // The same when there is a single role.
  $this
    ->drupalGet($job
    ->toUrl());
  $this
    ->assertText(t('@translator can not translate from @source to @target.', array(
    '@translator' => 'Drupal user',
    '@source' => 'English',
    '@target' => 'German',
  )));

  // Create another local translator with the required abilities.
  $other_assignee_same = $this
    ->drupalCreateUser($this->localTranslatorPermissions);

  // And test again with two roles but still no abilities.
  $this
    ->drupalGet($job
    ->toUrl());
  $this
    ->assertText(t('@translator can not translate from @source to @target.', array(
    '@translator' => 'Drupal user',
    '@source' => 'English',
    '@target' => 'German',
  )));
  $this
    ->drupalLogin($other_assignee_same);

  // Configure language abilities.
  $edit = array(
    'tmgmt_translation_skills[0][language_from]' => 'en',
    'tmgmt_translation_skills[0][language_to]' => 'de',
  );
  $this
    ->drupalPostForm('user/' . $other_assignee_same
    ->id() . '/edit', $edit, t('Save'));

  // Check that the user is not listed in the translator selection form.
  $this
    ->loginAsAdmin();
  $this
    ->drupalGet($job
    ->toUrl());
  $element = $this
    ->xpath('//*[@id="edit-translator"]/option')[0];
  $this
    ->assertEqual($element
    ->getText(), 'Drupal user');
  $this
    ->assertText(t('Assign job to'));
  $this
    ->assertText($other_assignee_same
    ->getDisplayName());
  $this
    ->assertNoText($this->assignee
    ->getDisplayName());
  $this
    ->drupalLogin($this->assignee);

  // Configure language abilities.
  $edit = array(
    'tmgmt_translation_skills[0][language_from]' => 'en',
    'tmgmt_translation_skills[0][language_to]' => 'de',
  );
  $this
    ->drupalPostForm('user/' . $this->assignee
    ->id() . '/edit', $edit, t('Save'));

  // Check that the translator is now listed.
  $this
    ->loginAsAdmin();
  $this
    ->drupalGet($job
    ->toUrl());
  $this
    ->assertText($this->assignee
    ->getDisplayName());

  // Test assign task while submitting job.
  $job_comment = 'Dummy job comment';
  $edit = [
    'settings[translator]' => $this->assignee
      ->id(),
    'settings[job_comment]' => $job_comment,
  ];
  $this
    ->drupalPostForm(NULL, $edit, t('Submit to provider'));
  $this
    ->drupalLogin($this->assignee);
  $this
    ->drupalGet('translate/pending');
  $this
    ->assertText($job
    ->label());
  $this
    ->loginAsAdmin($this->localManagerPermissions);
  $this
    ->drupalGet('manage-translate/assigned');
  $this
    ->assertNoLink(t('Delete'));
  $this
    ->clickLink(t('Unassign'));
  $this
    ->drupalPostForm(NULL, [], t('Unassign'));

  // Test for job comment in the job checkout info pane.
  $this
    ->drupalGet($job
    ->toUrl());
  $this
    ->assertText($job_comment);
  $this
    ->drupalLogin($this->assignee);

  // Create a second local translator with different language abilities,
  // make sure that he does not see the task.
  $other_translator = $this
    ->drupalCreateUser($this->localTranslatorPermissions);
  $this
    ->drupalLogin($other_translator);

  // Configure language abilities.
  $edit = array(
    'tmgmt_translation_skills[0][language_from]' => 'de',
    'tmgmt_translation_skills[0][language_to]' => 'en',
  );
  $this
    ->drupalPostForm('user/' . $other_translator
    ->id() . '/edit', $edit, t('Save'));
  $this
    ->drupalGet('translate');
  $this
    ->assertNoText($job
    ->label());
  $this
    ->drupalLogin($this->assignee);

  // Check the translate overview.
  $this
    ->drupalGet('translate');
  $this
    ->assertText($job
    ->label());

  // @todo: Fails, encoding problem?
  // $this->assertText(t('@from => @to', array('@from' => 'en', '@to' => 'de')));
  // Test LocalTaskForm.
  $this
    ->clickLink('View');
  $this
    ->assertText('Unassigned');
  $xpath = $this
    ->xpath('//*[@id="edit-status"]');
  $this
    ->assertEmpty($xpath);
  $this
    ->loginAsAdmin($this->localManagerPermissions);
  $this
    ->drupalGet('translate');
  $this
    ->clickLink('View');
  $xpath = $this
    ->xpath('//*[@id="edit-tuid"]');
  $this
    ->assertNotEmpty($xpath);
  $edit = array(
    'tuid' => $this->assignee
      ->id(),
  );
  $this
    ->drupalPostForm(NULL, $edit, t('Save task'));
  $this
    ->assertText(t('Assigned to user @assignee.', [
    '@assignee' => $this->assignee
      ->getDisplayName(),
  ]));
  $this
    ->drupalGet('manage-translate/assigned');
  $this
    ->clickLink('View');
  $edit = array(
    'tuid' => 0,
  );
  $this
    ->drupalPostForm(NULL, $edit, t('Save task'));
  $this
    ->drupalLogin($this->assignee);
  $this
    ->drupalGet('translate');

  // Assign to action not working yet.
  $edit = array(
    'tmgmt_local_task_bulk_form[0]' => TRUE,
    'action' => 'tmgmt_local_task_assign_to_me',
  );
  $this
    ->drupalPostForm(NULL, $edit, t('Apply to selected items'));
  $this
    ->assertText(t('Assign to me was applied to 1 item.'));

  // Unassign again.
  $edit = array(
    'tmgmt_local_task_bulk_form[0]' => TRUE,
    'action' => 'tmgmt_local_task_unassign_multiple',
  );
  $this
    ->drupalPostForm(NULL, $edit, t('Apply to selected items'));
  $this
    ->assertText(t('Unassign was applied to 1 item.'));

  // Now test the assign link.
  // @todo Action should not redirect to mine.
  $this
    ->drupalGet('translate');
  $this
    ->clickLink(t('Assign to me'));
  $this
    ->assertText(t('The task has been assigned to you.'));

  // Assert created local task and task items.
  $this
    ->drupalGet('translate/pending');
  $this
    ->clickLink(t('View'));
  $this
    ->assertNotEmpty(preg_match('|translate/(\\d+)|', $this
    ->getUrl(), $matches), 'Task found');

  /** @var \Drupal\tmgmt_local\Entity\LocalTask $task */
  $task = \Drupal::entityTypeManager()
    ->getStorage('tmgmt_local_task')
    ->load($matches[1]);
  $this
    ->assertTrue($task
    ->isPending());
  $items = $task
    ->getItems();

  /** @var \Drupal\tmgmt_local\Entity\LocalTaskItem $first_task_item */
  $first_task_item = reset($items);
  $this
    ->assertTrue($first_task_item
    ->isPending());

  // Log in with the translator with the same abilities, make sure that he
  // does not see the assigned task.
  $this
    ->drupalLogin($other_assignee_same);
  $this
    ->drupalGet('translate');
  $this
    ->assertNoText($job
    ->label());
  $this
    ->drupalGet('translate/items/' . $first_task_item
    ->id());
  $this
    ->assertResponse(403);
  $this
    ->drupalLogin($this->admin_user);

  // Unassign the task.
  $this
    ->drupalGet('translate/' . $task
    ->id());
  $edit = [
    'tuid' => '',
  ];
  $this
    ->drupalPostForm(NULL, $edit, t('Save task'));
  $this
    ->clickLink(t('View'));

  // Assign again the task to himself.
  $edit = [
    'tuid' => $this->assignee
      ->id(),
  ];
  $this
    ->drupalPostForm(NULL, $edit, t('Save task'));
  $this
    ->drupalLogin($this->assignee);

  // Translate the task.
  $this
    ->drupalGet('translate/' . $task
    ->id());
  $this
    ->assertText('test_source:test:1');
  $this
    ->assertText('test_source:test:2');

  // Translate the first item.
  $this
    ->drupalGet($first_task_item
    ->toUrl());

  // Assert the breadcrumb.
  $this
    ->assertLink(t('Home'));
  $this
    ->assertLink(t('Local Tasks'));
  $this
    ->assertText($job
    ->label());

  // Assert the header.
  $this
    ->assertLink($first_task_item
    ->getJobItem()
    ->getSourceLabel());
  $this
    ->assertText($first_task_item
    ->getJobItem()
    ->getSourceType());
  $this
    ->assertText($first_task_item
    ->getJobItem()
    ->getJob()
    ->getSourceLanguage()
    ->getName());
  $this
    ->assertText($first_task_item
    ->getJobItem()
    ->getJob()
    ->getTargetLanguage()
    ->getName());
  $this
    ->assertText(\Drupal::service('date.formatter')
    ->format($first_task_item
    ->getChangedTime()));
  $this
    ->assertText($first_task_item
    ->getStatus());
  $this
    ->assertLink($first_task_item
    ->getTask()
    ->label());
  $this
    ->assertText(t('Dummy'));

  // Check if Save as completed button is displayed.
  $elements = $this
    ->xpath('//*[@id="edit-save-as-completed"]');
  $this
    ->assertTrue(!empty($elements), "'Save as completed' button appears.");

  // Job comment is present in the translate tool as well.
  $this
    ->assertText($job_comment);
  $this
    ->assertText('test_source:test:1');

  // Try to complete a translation when translations are missing.
  $edit = array(
    'dummy|deep_nesting[translation]' => '',
  );
  $this
    ->drupalPostForm(NULL, $edit, t('Save as completed'));
  $this
    ->assertText(t('Missing translation.'));
  $edit = array(
    'dummy|deep_nesting[translation]' => $translation1 = 'German translation of source 1',
  );
  $this
    ->drupalPostForm(NULL, $edit, t('Save as completed'));
  $this
    ->assertRaw('tmgmt/icons/gray-check.svg" title="Translated"');
  $this
    ->assertText('The translation for ' . $first_task_item
    ->label() . ' has been saved as completed.');

  // Check that the source has not being modified.
  $this
    ->clickLink(t('View'));

  /** @var \Drupal\tmgmt\JobItemInterface $job_item */
  $job_items = $job
    ->getItems([
    'tjiid' => 1,
  ]);
  $job_item = reset($job_items);
  $source = $job_item
    ->getData([
    'dummy',
    'deep_nesting',
    '#text',
  ]);
  $this
    ->assertText($source);

  // Review and accept the first item.
  \Drupal::entityTypeManager()
    ->getStorage('tmgmt_job_item')
    ->resetCache();
  drupal_static_reset('tmgmt_local_task_statistics_load');

  /** @var \Drupal\tmgmt\JobItemInterface $item1 */
  $item1 = JobItem::load(1);

  // The first item should be available for review.
  $this
    ->assertTrue($item1
    ->isNeedsReview(), 'Job item 1 needs review.');
  $item1
    ->acceptTranslation();

  // The first item should be accepted now, the second still in progress.
  \Drupal::entityTypeManager()
    ->getStorage('tmgmt_local_task_item')
    ->resetCache();
  $this
    ->drupalGet('translate/1');

  // Checking if the 'Save as completed' button is not displayed.
  $this
    ->drupalGet('translate/items/1');
  $elements = $this
    ->xpath('//*[@id="edit-save-as-completed"]');
  $this
    ->assertTrue(empty($elements), "'Save as completed' button does not appear.");

  // Checking if the item status is not displayed.
  $this
    ->assertNoRaw('title="Finish"');
  $this
    ->assertNoRaw('title="Reject"');

  // We can go back to the Task from the item.
  $this
    ->drupalGet('translate/items/1');
  $this
    ->clickLink($task
    ->label());

  // Let's check the task status.

  /** @var \Drupal\tmgmt_local\Entity\LocalTask $task */
  $task = \Drupal::entityTypeManager()
    ->getStorage('tmgmt_local_task')
    ->loadUnchanged($task
    ->id());
  $this
    ->assertTrue($task
    ->isPending());

  /** @var \Drupal\tmgmt_local\Entity\LocalTaskItem $second_task_item */
  list($first_task_item, $second_task_item) = array_values($task
    ->getItems());
  $this
    ->assertTrue($first_task_item
    ->isClosed());

  // Assert that translator can provide translations for a "Dummy" field. An
  // empty text field should be displayed as translator does not have a
  // permission to use "full_html" text format.
  $second_task_item
    ->updateData('dummy|deep_nesting', [
    '#format' => 'full_html',
  ]);
  $second_task_item
    ->save();
  $this
    ->clickLink(t('Translate'));
  $this
    ->assertFieldByName('dummy|deep_nesting[translation]');
  $this
    ->assertRaw('Save as completed" class="button button--primary js-form-submit form-submit"');
  $translation_field = $this
    ->xpath('//*[@id="edit-dummydeep-nesting-translation"]')[0];
  $this
    ->assertEqual($translation_field
    ->getText(), '');

  // Translate the second item but do not mark as translated it yet.
  $second_task_item
    ->updateData('dummy|deep_nesting', [
    '#format' => 'basic_html',
  ]);
  $second_task_item
    ->save();
  $this
    ->drupalGet('translate/items/' . $second_task_item
    ->id());
  $title = $this
    ->xpath('//*[@id="edit-dummydeep-nesting-translation-format-guidelines"]/div/h4')[0];
  $this
    ->assertEqual($title
    ->getText(), t('Basic HTML'));

  // Assert the order of the displayed elements.
  $translate_elements = $this
    ->xpath('//*[@id="edit-translation"]/table');
  $ids = [];
  foreach ($translate_elements as $translate_element) {
    $ids[] = (string) $translate_element
      ->getAttribute('id');
  }
  $this
    ->assertEqual($ids[0], 'tmgmt-local-element-dummy-deep-nesting');
  $this
    ->assertEqual($ids[1], 'tmgmt-local-element-second');
  $this
    ->assertEqual($ids[2], 'tmgmt-local-element-third');
  $edit = array(
    'dummy|deep_nesting[translation][value]' => $translation2 = 'German translation of source 2',
  );
  $this
    ->drupalPostForm(NULL, $edit, t('Save'));
  $this
    ->assertText('The translation for ' . $second_task_item
    ->label() . ' has been saved.');
  drupal_static_reset('tmgmt_local_task_statistics_load');

  /** @var \Drupal\tmgmt_local\Entity\LocalTask $task */
  $task = \Drupal::entityTypeManager()
    ->getStorage('tmgmt_local_task')
    ->loadUnchanged($task
    ->id());
  $this
    ->assertTrue($task
    ->isPending());

  // Mark the data item as translated but don't save the task item as
  // completed.
  $this
    ->clickLink(t('Translate'));
  $page = $this
    ->getSession()
    ->getPage();
  $page
    ->pressButton('finish-dummy|deep_nesting');
  $this
    ->assertRaw('name="reject-dummy|deep_nesting"', "'✗' button appears.");
  $this
    ->drupalGet('translate/' . $task
    ->id());
  \Drupal::entityTypeManager()
    ->getStorage('tmgmt_local_task_item')
    ->resetCache();
  drupal_static_reset('tmgmt_local_task_statistics_load');

  /** @var \Drupal\tmgmt_local\Entity\LocalTask $task */
  $task = \Drupal::entityTypeManager()
    ->getStorage('tmgmt_local_task')
    ->loadUnchanged($task
    ->id());
  $this
    ->assertTrue($task
    ->isPending());
  list($first_task_item, $second_task_item) = array_values($task
    ->getItems());
  $this
    ->assertTrue($first_task_item
    ->isClosed());
  $this
    ->assertTrue($second_task_item
    ->isPending());

  // Check the job data.
  \Drupal::entityTypeManager()
    ->getStorage('tmgmt_job_item')
    ->resetCache();

  /** @var \Drupal\tmgmt\JobInterface $job */
  $job = Job::load($job
    ->id());

  /** @var \Drupal\tmgmt\JobItemInterface $item2 */
  list($item1, $item2) = array_values($job
    ->getItems());
  $this
    ->assertTrue($item1
    ->isAccepted(), 'Job item 1 is accepted.');

  // The first item should be active.
  $this
    ->assertTrue($item2
    ->isActive(), 'Job item 2 is still active.');

  // Check the overview page, the task should still show in progress.
  $this
    ->drupalGet('translate');
  $this
    ->assertText(t('Pending'));

  // Mark the second item as completed now.
  $this
    ->clickLink(t('View'));
  $this
    ->clickLink(t('Translate'));
  $remaining_translations = [
    'second[translation]' => 'Third translation',
    'third[translation]' => 'Third translation',
  ];
  $this
    ->drupalPostForm(NULL, $remaining_translations, t('Save as completed'));
  $this
    ->assertText('The translation for ' . $second_task_item
    ->label() . ' has been saved as completed.');
  $this
    ->clickLink('View');

  // Review and accept the second item.
  \Drupal::entityTypeManager()
    ->getStorage('tmgmt_job_item')
    ->resetCache();
  drupal_static_reset('tmgmt_local_task_statistics_load');
  $item1 = JobItem::load(2);
  $item1
    ->acceptTranslation();

  // Refresh the page.
  $this
    ->drupalGet('translate');

  // We should have been redirect back to the overview, the task should be
  // completed now.
  $this
    ->assertNoText($task
    ->getJob()
    ->label());
  $this
    ->clickLink(t('Closed'));
  $this
    ->assertText($task
    ->getJob()
    ->label());
  $this
    ->assertText(t('Completed'));
  \Drupal::entityTypeManager()
    ->getStorage('tmgmt_local_task_item')
    ->resetCache();
  $task = LocalTask::load($task
    ->id());
  $this
    ->assertTrue($task
    ->isClosed());
  list($first_task_item, $second_task_item) = array_values($task
    ->getItems());
  $this
    ->assertTrue($first_task_item
    ->isClosed());
  $this
    ->assertTrue($second_task_item
    ->isClosed());
  \Drupal::entityTypeManager()
    ->getStorage('tmgmt_job_item')
    ->resetCache();
  $job = Job::load($job
    ->id());
  list($item1, $item2) = array_values($job
    ->getItems());

  // Job was accepted and finished automatically due to the default approve
  // setting.
  $this
    ->assertTrue($job
    ->isFinished());
  $this
    ->assertEqual($item1
    ->getData(array(
    'dummy',
    'deep_nesting',
    '#translation',
    '#text',
  )), $translation1);
  $this
    ->assertEqual($item2
    ->getData(array(
    'dummy',
    'deep_nesting',
    '#translation',
    '#text',
  )), $translation2);

  // Delete the job, make sure that the corresponding task and task items were
  // deleted.
  $job
    ->delete();
  $this
    ->assertEmpty(LocalTask::load($task
    ->id()));
  $this
    ->assertEmpty($task
    ->getItems());
}