View source  
  <?php
namespace Drupal\Tests\lingotek\Functional;
use Drupal\Core\Url;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\language\Entity\ContentLanguageSettings;
use Drupal\lingotek\Lingotek;
use Drupal\node\Entity\Node;
use Drupal\Tests\TestFileCreationTrait;
class LingotekNodeTranslationTest extends LingotekTestBase {
  use TestFileCreationTrait;
  
  public static $modules = [
    'block',
    'node',
    'image',
    'frozenintime',
  ];
  
  protected $node;
  
  protected function setUp() : void {
    parent::setUp();
    
    $this
      ->drupalPlaceBlock('page_title_block', [
      'region' => 'content',
      'weight' => -5,
    ]);
    $this
      ->drupalPlaceBlock('local_tasks_block', [
      'region' => 'content',
      'weight' => -10,
    ]);
    
    if ($this->profile != 'standard') {
      $this
        ->drupalCreateContentType([
        'type' => 'article',
        'name' => 'Article',
      ]);
    }
    $this
      ->createImageField('field_image', 'article');
    
    ConfigurableLanguage::createFromLangcode('es')
      ->setThirdPartySetting('lingotek', 'locale', 'es_MX')
      ->save();
    
    ContentLanguageSettings::loadByEntityTypeBundle('node', 'article')
      ->setLanguageAlterable(TRUE)
      ->save();
    \Drupal::service('content_translation.manager')
      ->setEnabled('node', 'article', TRUE);
    drupal_static_reset();
    \Drupal::entityTypeManager()
      ->clearCachedDefinitions();
    $this
      ->applyEntityUpdates();
    
    $this
      ->rebuildContainer();
    $this
      ->saveLingotekContentTranslationSettings([
      'node' => [
        'article' => [
          'profiles' => 'automatic',
          'fields' => [
            'title' => 1,
            'body' => 1,
            'field_image' => [
              'alt',
            ],
          ],
        ],
      ],
    ]);
  }
  
  public function testNodeTranslation() {
    
    $this
      ->drupalLogin($this->rootUser);
    $test_image = current($this
      ->getTestFiles('image'));
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool';
    $edit['body[0][value]'] = 'Llamas are very cool';
    $edit['langcode[0][value]'] = 'en';
    $edit['files[field_image_0]'] = \Drupal::service('file_system')
      ->realpath($test_image->uri);
    $this
      ->drupalPostForm('node/add/article', $edit, t('Preview'));
    unset($edit['files[field_image_0]']);
    $edit['field_image[0][alt]'] = 'Llamas are cool';
    $this
      ->saveAndPublishNodeForm($edit, NULL);
    $this->node = Node::load(1);
    
    $this
      ->drupalGet('node/1');
    $this
      ->clickLink('Translate');
    
    $data = json_decode(\Drupal::state()
      ->get('lingotek.uploaded_content', '[]'), TRUE);
    $this
      ->assertUploadedDataFieldCount($data, 3);
    $this
      ->assertTrue(isset($data['title'][0]['value']));
    $this
      ->assertEqual(1, count($data['body'][0]));
    $this
      ->assertTrue(isset($data['body'][0]['value']));
    $this
      ->assertEqual(1, count($data['field_image'][0]));
    $this
      ->assertTrue(isset($data['field_image'][0]['alt']));
    $this
      ->assertIdentical('en_US', \Drupal::state()
      ->get('lingotek.uploaded_locale'));
    
    $used_profile = \Drupal::state()
      ->get('lingotek.used_profile');
    $this
      ->assertIdentical('automatic', $used_profile, 'The automatic profile was used.');
    
    $translation_service = \Drupal::service('lingotek.content_translation');
    $source_status = $translation_service
      ->getSourceStatus($this->node);
    $this
      ->assertEqual(Lingotek::STATUS_IMPORTING, $source_status, 'The node has been marked as importing.');
    
    $metadata = $this->node->lingotek_metadata->entity;
    $expected_time = \Drupal::time()
      ->getRequestTime();
    $this
      ->assertEmpty($metadata
      ->getLastUpdated());
    $this
      ->assertEquals($expected_time, $metadata
      ->getLastUploaded());
    
    $this
      ->clickLink('Check Upload Status');
    $this
      ->assertText('The import for node Llamas are cool is complete.');
    
    $this
      ->assertLingotekRequestTranslationLink('es_MX');
    $this
      ->assertNoLingotekRequestTranslationLink('es_MX', 'dummy-document-hash-id', 'node', 'es');
    
    $this
      ->clickLink('Request translation');
    $this
      ->assertText("Locale 'es_MX' was added as a translation target for node Llamas are cool.");
    $this
      ->assertIdentical('es_MX', \Drupal::state()
      ->get('lingotek.added_target_locale'));
    
    $this
      ->clickLink('Check translation status');
    $this
      ->assertIdentical('es_MX', \Drupal::state()
      ->get('lingotek.checked_target_locale'));
    $this
      ->assertText('The es_MX translation for node Llamas are cool is ready for download.');
    
    $this
      ->assertLingotekWorkbenchLink('es_MX');
    
    $this
      ->clickLink('Download completed translation');
    $this
      ->assertText('The translation of node Llamas are cool into es_MX has been downloaded.');
    $this
      ->assertIdentical('es_MX', \Drupal::state()
      ->get('lingotek.downloaded_locale'));
    
    $this
      ->clickLink('Las llamas son chulas');
    $this
      ->assertText('Las llamas son chulas');
    $this
      ->assertText('Las llamas son muy chulas');
  }
  
  public function testNodeTranslationMessageWhenBundleNotConfigured() {
    $assert_session = $this
      ->assertSession();
    
    $this
      ->drupalCreateContentType([
      'type' => 'page',
      'name' => 'Page',
    ]);
    
    ContentLanguageSettings::loadByEntityTypeBundle('node', 'page')
      ->setLanguageAlterable(TRUE)
      ->save();
    \Drupal::service('content_translation.manager')
      ->setEnabled('node', 'page', TRUE);
    
    $edit = [];
    $edit['title[0][value]'] = 'Pages are cool';
    $edit['body[0][value]'] = 'Pages are very cool';
    $edit['langcode[0][value]'] = 'en';
    $this
      ->drupalPostForm('node/add/page', $edit, t('Save'));
    
    $this
      ->drupalGet('node/1');
    $this
      ->clickLink('Translate');
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $assert_session
      ->pageTextContains('Cannot upload Page Pages are cool. That Content type is not enabled for Lingotek translation.');
    $assert_session
      ->pageTextContains('Uploaded 0 documents to Lingotek.');
  }
  
  public function testNodeWithManualTranslation() {
    $assert_session = $this
      ->assertSession();
    
    $this
      ->drupalLogin($this->rootUser);
    $test_image = current($this
      ->getTestFiles('image'));
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool';
    $edit['body[0][value]'] = 'Llamas are very cool';
    $edit['langcode[0][value]'] = 'en';
    $edit['files[field_image_0]'] = \Drupal::service('file_system')
      ->realpath($test_image->uri);
    $edit['lingotek_translation_management[lingotek_translation_profile]'] = 'manual';
    $this
      ->drupalPostForm('node/add/article', $edit, t('Preview'));
    unset($edit['files[field_image_0]']);
    $edit['field_image[0][alt]'] = 'Llamas are cool';
    $this
      ->saveAndPublishNodeForm($edit, NULL);
    $this->node = Node::load(1);
    
    $translation_service = \Drupal::service('lingotek.content_translation');
    $source_status = $translation_service
      ->getSourceStatus($this->node);
    $this
      ->assertEqual(Lingotek::STATUS_UNTRACKED, $source_status, 'The node has been marked as untracked.');
    
    $this
      ->drupalGet('node/1');
    $this
      ->clickLink('Translate');
    
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('Uploaded 1 document to Lingotek.');
    
    $data = json_decode(\Drupal::state()
      ->get('lingotek.uploaded_content', '[]'), TRUE);
    $this
      ->assertUploadedDataFieldCount($data, 3);
    $this
      ->assertTrue(isset($data['title'][0]['value']));
    $this
      ->assertEqual(1, count($data['body'][0]));
    $this
      ->assertTrue(isset($data['body'][0]['value']));
    $this
      ->assertEqual(1, count($data['field_image'][0]));
    $this
      ->assertTrue(isset($data['field_image'][0]['alt']));
    $this
      ->assertIdentical('en_US', \Drupal::state()
      ->get('lingotek.uploaded_locale'));
    
    $used_profile = \Drupal::state()
      ->get('lingotek.used_profile');
    $this
      ->assertIdentical('manual', $used_profile, 'The automatic profile was used.');
    
    $this
      ->clickLink('Check Upload Status');
    $this
      ->assertText('The import for node Llamas are cool is complete.');
    
    $this
      ->assertLingotekRequestTranslationLink('es_MX');
    $this
      ->assertNoLingotekRequestTranslationLink('es_MX', 'dummy-document-hash-id', 'node', 'es');
    
    $this
      ->clickLink('Request translation');
    $this
      ->assertText("Locale 'es_MX' was added as a translation target for node Llamas are cool.");
    $this
      ->assertIdentical('es_MX', \Drupal::state()
      ->get('lingotek.added_target_locale'));
    
    $this
      ->clickLink('Check translation status');
    $this
      ->assertIdentical('es_MX', \Drupal::state()
      ->get('lingotek.checked_target_locale'));
    $this
      ->assertText('The es_MX translation for node Llamas are cool is ready for download.');
    
    $this
      ->assertLingotekWorkbenchLink('es_MX');
    
    $this
      ->clickLink('Download completed translation');
    $this
      ->assertText('The translation of node Llamas are cool into es_MX has been downloaded.');
    $this
      ->assertIdentical('es_MX', \Drupal::state()
      ->get('lingotek.downloaded_locale'));
    $assert_session
      ->linkNotExists('Download completed translation');
    $assert_session
      ->linkExists('Re-download completed translation');
    
    $this
      ->clickLink('Las llamas son chulas');
    $this
      ->assertText('Las llamas son chulas');
    $this
      ->assertText('Las llamas son muy chulas');
  }
  
  public function testEditedNodeTranslation() {
    
    $this
      ->testNodeTranslation();
    
    ConfigurableLanguage::createFromLangcode('eu')
      ->setThirdPartySetting('lingotek', 'locale', 'eu_ES')
      ->save();
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool EDITED';
    $edit['body[0][value]'] = 'Llamas are very cool EDITED';
    $edit['langcode[0][value]'] = 'en';
    $edit['lingotek_translation_management[lingotek_translation_profile]'] = 'automatic';
    $this
      ->saveAndKeepPublishedThisTranslationNodeForm($edit, 1);
    
    $this->node = $this
      ->resetStorageCachesAndReloadNode();
    $metadata = $this->node->lingotek_metadata->entity;
    $expected_time = \Drupal::time()
      ->getRequestTime();
    $this
      ->assertEquals($expected_time, $metadata
      ->getLastUpdated());
    $this
      ->assertEquals($expected_time, $metadata
      ->getLastUploaded());
    $this
      ->clickLink('Translate');
    
    $this
      ->assertLingotekRequestTranslationLink('eu_ES', 'dummy-document-hash-id-1');
    $this
      ->assertNoLingotekRequestTranslationLink('es_MX', 'dummy-document-hash-id-1');
    
    $this
      ->clickLink('Check translation status');
    $this
      ->assertText('The es_MX translation for node Llamas are cool EDITED is ready for download.');
    
    $this
      ->clickLink('Download completed translation');
    $this
      ->assertText('The translation of node Llamas are cool EDITED into es_MX has been downloaded.');
    $this
      ->clickLink('Las llamas son chulas');
    $this
      ->assertText('Las llamas son muy chulas');
  }
  
  public function testEditedNodeTranslationWhenBodyRemoved() {
    
    $this
      ->testNodeTranslation();
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool EDITED';
    $edit['body[0][value]'] = '';
    $edit['langcode[0][value]'] = 'en';
    $edit['lingotek_translation_management[lingotek_translation_profile]'] = 'automatic';
    $this
      ->saveAndKeepPublishedThisTranslationNodeForm($edit, 1);
    $this
      ->clickLink('Translate');
    
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('Uploaded 1 document to Lingotek.');
    
    $data = json_decode(\Drupal::state()
      ->get('lingotek.uploaded_content', '[]'), TRUE);
    $this
      ->assertUploadedDataFieldCount($data, 3);
    $this
      ->assertTrue(isset($data['title'][0]['value']));
    $this
      ->assertTrue(isset($data['body']));
    $this
      ->assertEmpty(count($data['body']));
    \Drupal::state()
      ->set('lingotek.uploaded_content_type', 'node+emptybody');
    
    $this
      ->clickLink('Check translation status');
    $this
      ->assertText('The es_MX translation for node Llamas are cool EDITED is ready for download.');
    
    $this
      ->clickLink('Download completed translation');
    $this
      ->assertText('The translation of node Llamas are cool EDITED into es_MX has been downloaded.');
    $this
      ->clickLink('Las llamas son chulas EDITADO');
    $this
      ->assertNoText('Las llamas son muy chulas');
  }
  
  public function testAddingContentInDifferentLocale() {
    
    $this
      ->drupalLogin($this->rootUser);
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool es-MX';
    $edit['body[0][value]'] = 'Llamas are very cool es-MX';
    $edit['langcode[0][value]'] = 'es';
    $this
      ->saveAndPublishNodeForm($edit);
    $this
      ->assertText('Llamas are cool es-MX sent to Lingotek successfully.');
    $this
      ->assertIdentical('es_MX', \Drupal::state()
      ->get('lingotek.uploaded_locale'));
  }
  
  public function testCannotAssignProfileToContentWithoutRightPermission() {
    $editor = $this
      ->drupalCreateUser([
      'bypass node access',
    ]);
    
    $this
      ->drupalLogin($editor);
    
    $this
      ->drupalGet('node/add/article');
    
    $this
      ->assertNoField('lingotek_translation_management[lingotek_translation_profile]');
    $translation_manager = $this
      ->drupalCreateUser([
      'bypass node access',
      'assign lingotek translation profiles',
    ]);
    
    $this
      ->drupalLogin($translation_manager);
    
    $this
      ->drupalGet('node/add/article');
    
    $this
      ->assertField('lingotek_translation_management[lingotek_translation_profile]');
  }
  
  public function testLanguageDisabled() {
    $assert_session = $this
      ->assertSession();
    
    $italian = ConfigurableLanguage::createFromLangcode('it')
      ->setThirdPartySetting('lingotek', 'locale', 'it_IT');
    $italian
      ->save();
    
    $this
      ->drupalLogin($this->rootUser);
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool';
    $edit['body[0][value]'] = 'Llamas are very cool';
    $edit['langcode[0][value]'] = 'en';
    $this
      ->saveAndPublishNodeForm($edit);
    $this->node = Node::load(1);
    
    $data = json_decode(\Drupal::state()
      ->get('lingotek.uploaded_content', '[]'), TRUE);
    $this
      ->assertUploadedDataFieldCount($data, 3);
    $this
      ->assertTrue(isset($data['title'][0]['value']));
    $this
      ->assertEqual(1, count($data['body'][0]));
    $this
      ->assertTrue(isset($data['body'][0]['value']));
    $this
      ->assertIdentical('en_US', \Drupal::state()
      ->get('lingotek.uploaded_locale'));
    
    $used_profile = \Drupal::state()
      ->get('lingotek.used_profile');
    $this
      ->assertIdentical('automatic', $used_profile, 'The automatic profile was used.');
    
    $this
      ->drupalGet('node/1');
    $this
      ->clickLink('Translate');
    
    $this
      ->clickLink('Check Upload Status');
    $this
      ->assertText('The import for node Llamas are cool is complete.');
    
    $this
      ->assertLingotekRequestTranslationLink('it_IT');
    $this
      ->assertLingotekRequestTranslationLink('es_MX');
    $assert_session
      ->linkByHrefExists('/node/1/translations/add/en/it');
    $assert_session
      ->linkByHrefExists('/node/1/translations/add/en/es');
    
    $lingotek_config = \Drupal::service('lingotek.configuration');
    $lingotek_config
      ->disableLanguage($italian);
    
    $this
      ->drupalGet('node/1/translations');
    
    $this
      ->assertNoLingotekRequestTranslationLink('it_IT');
    $this
      ->assertLingotekRequestTranslationLink('es_MX');
    $assert_session
      ->linkByHrefExists('/node/1/translations/add/en/it');
    $assert_session
      ->linkByHrefExists('/node/1/translations/add/en/es');
  }
  
  public function testUploadingWithAnError() {
    \Drupal::state()
      ->set('lingotek.must_error_in_upload', TRUE);
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool';
    $edit['body[0][value]'] = 'Llamas are very cool';
    $edit['langcode[0][value]'] = 'en';
    $edit['lingotek_translation_management[lingotek_translation_profile]'] = 'manual';
    $this
      ->saveAndPublishNodeForm($edit);
    
    $this
      ->drupalGet('node/1');
    $this
      ->clickLink('Translate');
    
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('The upload for node Llamas are cool failed. Please try again.');
    
    $this->node = Node::load(1);
    
    $translation_service = \Drupal::service('lingotek.content_translation');
    $source_status = $translation_service
      ->getSourceStatus($this->node);
    $this
      ->assertEqual(Lingotek::STATUS_ERROR, $source_status, 'The node has been marked as error.');
    $metadata = $this->node->lingotek_metadata->entity;
    $expected_time = \Drupal::time()
      ->getRequestTime();
    $this
      ->assertEmpty($metadata
      ->getLastUploaded());
    $this
      ->assertEmpty($metadata
      ->getLastUpdated());
    
    \Drupal::state()
      ->set('lingotek.must_error_in_upload', FALSE);
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('Uploaded 1 document to Lingotek.');
    $this->node = $this
      ->resetStorageCachesAndReloadNode();
    $metadata = $this->node->lingotek_metadata->entity;
    $this
      ->assertEquals($expected_time, $metadata
      ->getLastUploaded());
    $this
      ->assertEmpty($metadata
      ->getLastUpdated());
  }
  
  public function testUploadingWithAPaymentRequiredError() {
    \Drupal::state()
      ->set('lingotek.must_payment_required_error_in_upload', TRUE);
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool';
    $edit['body[0][value]'] = 'Llamas are very cool';
    $edit['langcode[0][value]'] = 'en';
    $edit['lingotek_translation_management[lingotek_translation_profile]'] = 'manual';
    $this
      ->saveAndPublishNodeForm($edit);
    
    $this
      ->drupalGet('node/1');
    $this
      ->clickLink('Translate');
    
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('Community has been disabled. Please contact support@lingotek.com to re-enable your community.');
    
    $this->node = Node::load(1);
    
    $translation_service = \Drupal::service('lingotek.content_translation');
    $source_status = $translation_service
      ->getSourceStatus($this->node);
    $this
      ->assertEqual(Lingotek::STATUS_ERROR, $source_status, 'The node has been marked as error.');
    
    \Drupal::state()
      ->set('lingotek.must_payment_required_error_in_upload', FALSE);
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('Uploaded 1 document to Lingotek.');
  }
  
  public function testUpdatingWithAnError() {
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool';
    $edit['body[0][value]'] = 'Llamas are very cool';
    $edit['langcode[0][value]'] = 'en';
    $edit['lingotek_translation_management[lingotek_translation_profile]'] = 'manual';
    $this
      ->saveAndPublishNodeForm($edit);
    
    $this
      ->drupalGet('node/1');
    $this
      ->clickLink('Translate');
    
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('Uploaded 1 document to Lingotek.');
    
    $this
      ->clickLink('Check Upload Status');
    $this
      ->assertText('The import for node Llamas are cool is complete.');
    
    $edit['title[0][value]'] = 'Llamas are cool EDITED';
    $this
      ->saveAndKeepPublishedNodeForm($edit, 1);
    
    $this
      ->drupalGet('node/1');
    $this
      ->clickLink('Translate');
    \Drupal::state()
      ->set('lingotek.must_error_in_upload', TRUE);
    
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('The update for node Llamas are cool EDITED failed. Please try again.');
    
    $this->node = Node::load(1);
    
    $translation_service = \Drupal::service('lingotek.content_translation');
    $source_status = $translation_service
      ->getSourceStatus($this->node);
    $this
      ->assertEqual(Lingotek::STATUS_ERROR, $source_status, 'The node has been marked as error.');
    
    \Drupal::state()
      ->set('lingotek.must_error_in_upload', FALSE);
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('Uploaded 1 document to Lingotek.');
  }
  
  public function testUpdatingWithAPaymentRequiredError() {
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool';
    $edit['body[0][value]'] = 'Llamas are very cool';
    $edit['langcode[0][value]'] = 'en';
    $edit['lingotek_translation_management[lingotek_translation_profile]'] = 'manual';
    $this
      ->saveAndPublishNodeForm($edit);
    
    $this
      ->drupalGet('node/1');
    $this
      ->clickLink('Translate');
    
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('Uploaded 1 document to Lingotek.');
    
    $this
      ->clickLink('Check Upload Status');
    $this
      ->assertText('The import for node Llamas are cool is complete.');
    
    $edit['title[0][value]'] = 'Llamas are cool EDITED';
    $this
      ->saveAndKeepPublishedNodeForm($edit, 1);
    
    $this
      ->drupalGet('node/1');
    $this
      ->clickLink('Translate');
    \Drupal::state()
      ->set('lingotek.must_payment_required_error_in_update', TRUE);
    
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('Community has been disabled. Please contact support@lingotek.com to re-enable your community.');
    
    $this->node = Node::load(1);
    
    $translation_service = \Drupal::service('lingotek.content_translation');
    $source_status = $translation_service
      ->getSourceStatus($this->node);
    $this
      ->assertEqual(Lingotek::STATUS_ERROR, $source_status, 'The node has been marked as error.');
    
    \Drupal::state()
      ->set('lingotek.must_payment_required_error_in_update', FALSE);
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('Uploaded 1 document to Lingotek.');
  }
  
  public function testUpdatingWithADocumentArchivedError() {
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool';
    $edit['body[0][value]'] = 'Llamas are very cool';
    $edit['langcode[0][value]'] = 'en';
    $edit['lingotek_translation_management[lingotek_translation_profile]'] = 'manual';
    $this
      ->saveAndPublishNodeForm($edit);
    
    $this
      ->drupalGet('node/1');
    $this
      ->clickLink('Translate');
    
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('Uploaded 1 document to Lingotek.');
    
    $this
      ->clickLink('Check Upload Status');
    $this
      ->assertText('The import for node Llamas are cool is complete.');
    
    $edit['title[0][value]'] = 'Llamas are cool EDITED';
    $this
      ->saveAndKeepPublishedNodeForm($edit, 1);
    
    $this
      ->drupalGet('node/1');
    $this
      ->clickLink('Translate');
    \Drupal::state()
      ->set('lingotek.must_document_archived_error_in_update', TRUE);
    
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('Document node Llamas are cool EDITED has been archived. Please upload again.');
    
    $this->node = Node::load(1);
    
    $translation_service = \Drupal::service('lingotek.content_translation');
    $source_status = $translation_service
      ->getSourceStatus($this->node);
    $this
      ->assertEqual(Lingotek::STATUS_UNTRACKED, $source_status, 'The node has been marked as untracked, needs new upload.');
    
    \Drupal::state()
      ->set('lingotek.must_document_archived_error_in_update', FALSE);
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('Uploaded 1 document to Lingotek.');
  }
  
  public function testUpdatingWithADocumentArchivedErrorViaAutomaticUpload() {
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool';
    $edit['body[0][value]'] = 'Llamas are very cool';
    $edit['langcode[0][value]'] = 'en';
    $edit['lingotek_translation_management[lingotek_translation_profile]'] = 'automatic';
    $this
      ->saveAndPublishNodeForm($edit);
    \Drupal::state()
      ->set('lingotek.must_document_archived_error_in_update', TRUE);
    
    $edit['title[0][value]'] = 'Llamas are cool EDITED';
    $this
      ->saveAndKeepPublishedNodeForm($edit, 1);
    
    $this
      ->assertText('Document node Llamas are cool EDITED has been archived. Please upload again.');
    
    $this->node = Node::load(1);
    
    $translation_service = \Drupal::service('lingotek.content_translation');
    $source_status = $translation_service
      ->getSourceStatus($this->node);
    $this
      ->assertEqual(Lingotek::STATUS_UNTRACKED, $source_status, 'The node has been marked as untracked, needs new upload.');
  }
  
  public function testUpdatingWithADocumentLockedError() {
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool';
    $edit['body[0][value]'] = 'Llamas are very cool';
    $edit['langcode[0][value]'] = 'en';
    $edit['lingotek_translation_management[lingotek_translation_profile]'] = 'manual';
    $this
      ->saveAndPublishNodeForm($edit);
    
    $this
      ->drupalGet('node/1');
    $this
      ->clickLink('Translate');
    
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('Uploaded 1 document to Lingotek.');
    
    $this
      ->clickLink('Check Upload Status');
    $this
      ->assertText('The import for node Llamas are cool is complete.');
    
    $edit['title[0][value]'] = 'Llamas are cool EDITED';
    $this
      ->saveAndKeepPublishedNodeForm($edit, 1);
    
    $this
      ->drupalGet('node/1');
    $this
      ->clickLink('Translate');
    \Drupal::state()
      ->set('lingotek.must_document_locked_error_in_update', TRUE);
    
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('Document node Llamas are cool EDITED has a new version. The document id has been updated for all future interactions. Please try again.');
    
    $this->node = Node::load(1);
    
    $translation_service = \Drupal::service('lingotek.content_translation');
    $source_status = $translation_service
      ->getSourceStatus($this->node);
    $this
      ->assertEqual(Lingotek::STATUS_EDITED, $source_status, 'The node has been marked as edited, needs new upload.');
    
    \Drupal::state()
      ->set('lingotek.must_document_locked_error_in_update', FALSE);
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('Uploaded 1 document to Lingotek.');
  }
  
  public function testUpdatingWithADocumentLockedErrorViaAutomaticUpload() {
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool';
    $edit['body[0][value]'] = 'Llamas are very cool';
    $edit['langcode[0][value]'] = 'en';
    $edit['lingotek_translation_management[lingotek_translation_profile]'] = 'automatic';
    $this
      ->saveAndPublishNodeForm($edit);
    \Drupal::state()
      ->set('lingotek.must_document_locked_error_in_update', TRUE);
    
    $edit['title[0][value]'] = 'Llamas are cool EDITED';
    $this
      ->saveAndKeepPublishedNodeForm($edit, 1);
    
    $this
      ->assertText('Document node Llamas are cool EDITED has a new version. The document id has been updated for all future interactions. Please try again.');
    
    $this->node = Node::load(1);
    
    $translation_service = \Drupal::service('lingotek.content_translation');
    $source_status = $translation_service
      ->getSourceStatus($this->node);
    $this
      ->assertEqual(Lingotek::STATUS_EDITED, $source_status, 'The node has been marked as edited, needs new upload.');
  }
  
  public function testUploadingWithAnErrorViaAutomaticUpload() {
    \Drupal::state()
      ->set('lingotek.must_error_in_upload', TRUE);
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool';
    $edit['body[0][value]'] = 'Llamas are very cool';
    $edit['langcode[0][value]'] = 'en';
    $edit['lingotek_translation_management[lingotek_translation_profile]'] = 'automatic';
    $this
      ->saveAndPublishNodeForm($edit);
    
    $this
      ->assertText('The upload for node Llamas are cool failed. Please try again.');
    
    $this->node = Node::load(1);
    
    $translation_service = \Drupal::service('lingotek.content_translation');
    $source_status = $translation_service
      ->getSourceStatus($this->node);
    $this
      ->assertEqual(Lingotek::STATUS_ERROR, $source_status, 'The node has been marked as error.');
  }
  
  public function testUploadingWithAPaymentRequiredErrorViaAutomaticUpload() {
    \Drupal::state()
      ->set('lingotek.must_payment_required_error_in_upload', TRUE);
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool';
    $edit['body[0][value]'] = 'Llamas are very cool';
    $edit['langcode[0][value]'] = 'en';
    $edit['lingotek_translation_management[lingotek_translation_profile]'] = 'automatic';
    $this
      ->saveAndPublishNodeForm($edit);
    
    $this
      ->assertText('Community has been disabled. Please contact support@lingotek.com to re-enable your community.');
    
    $this->node = Node::load(1);
    
    $translation_service = \Drupal::service('lingotek.content_translation');
    $source_status = $translation_service
      ->getSourceStatus($this->node);
    $this
      ->assertEqual(Lingotek::STATUS_ERROR, $source_status, 'The node has been marked as error.');
  }
  
  public function testUpdatingWithAnErrorViaAutomaticUpload() {
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool';
    $edit['body[0][value]'] = 'Llamas are very cool';
    $edit['langcode[0][value]'] = 'en';
    $edit['lingotek_translation_management[lingotek_translation_profile]'] = 'automatic';
    $this
      ->saveAndPublishNodeForm($edit);
    \Drupal::state()
      ->set('lingotek.must_error_in_upload', TRUE);
    
    $edit['title[0][value]'] = 'Llamas are cool EDITED';
    $this
      ->saveAndKeepPublishedNodeForm($edit, 1);
    
    $this
      ->assertText('The update for node Llamas are cool EDITED failed. Please try again.');
    
    $this->node = Node::load(1);
    
    $translation_service = \Drupal::service('lingotek.content_translation');
    $source_status = $translation_service
      ->getSourceStatus($this->node);
    $this
      ->assertEqual(Lingotek::STATUS_ERROR, $source_status, 'The node has been marked as error.');
  }
  
  public function testUpdatingWithAPaymentRequiredErrorViaAutomaticUpload() {
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool';
    $edit['body[0][value]'] = 'Llamas are very cool';
    $edit['langcode[0][value]'] = 'en';
    $edit['lingotek_translation_management[lingotek_translation_profile]'] = 'automatic';
    $this
      ->saveAndPublishNodeForm($edit);
    \Drupal::state()
      ->set('lingotek.must_payment_required_error_in_update', TRUE);
    
    $edit['title[0][value]'] = 'Llamas are cool EDITED';
    $this
      ->saveAndKeepPublishedNodeForm($edit, 1);
    
    $this
      ->assertText('Community has been disabled. Please contact support@lingotek.com to re-enable your community.');
    
    $this->node = Node::load(1);
    
    $translation_service = \Drupal::service('lingotek.content_translation');
    $source_status = $translation_service
      ->getSourceStatus($this->node);
    $this
      ->assertEqual(Lingotek::STATUS_ERROR, $source_status, 'The node has been marked as error.');
  }
  
  public function testRequestTranslationWithAnError() {
    \Drupal::state()
      ->set('lingotek.must_error_in_request_translation', TRUE);
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool';
    $edit['body[0][value]'] = 'Llamas are very cool';
    $edit['langcode[0][value]'] = 'en';
    $edit['lingotek_translation_management[lingotek_translation_profile]'] = 'manual';
    $this
      ->saveAndPublishNodeForm($edit);
    
    $this
      ->drupalGet('node/1');
    $this
      ->clickLink('Translate');
    
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('Uploaded 1 document to Lingotek.');
    
    $this
      ->clickLink('Check Upload Status');
    $this
      ->assertText('The import for node Llamas are cool is complete.');
    
    $this
      ->clickLink('Request translation');
    
    $this
      ->assertText('The translation request for node failed. Please try again.');
    
    $this->node = Node::load(1);
    
    $translation_service = \Drupal::service('lingotek.content_translation');
    $source_status = $translation_service
      ->getSourceStatus($this->node);
    $this
      ->assertEqual(Lingotek::STATUS_CURRENT, $source_status, 'The node has not been marked as error.');
  }
  
  public function testRequestTranslationWithAPaymentRequiredError() {
    \Drupal::state()
      ->set('lingotek.must_payment_required_error_in_request_translation', TRUE);
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool';
    $edit['body[0][value]'] = 'Llamas are very cool';
    $edit['langcode[0][value]'] = 'en';
    $edit['lingotek_translation_management[lingotek_translation_profile]'] = 'manual';
    $this
      ->saveAndPublishNodeForm($edit);
    
    $this
      ->drupalGet('node/1');
    $this
      ->clickLink('Translate');
    
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('Uploaded 1 document to Lingotek.');
    
    $this
      ->clickLink('Check Upload Status');
    $this
      ->assertText('The import for node Llamas are cool is complete.');
    
    $this
      ->clickLink('Request translation');
    $this
      ->assertText('Community has been disabled. Please contact support@lingotek.com to re-enable your community.');
    $this->node = Node::load(1);
    
    $translation_service = \Drupal::service('lingotek.content_translation');
    $source_status = $translation_service
      ->getSourceStatus($this->node);
    $this
      ->assertEqual($source_status, Lingotek::STATUS_CURRENT);
    $this
      ->assertEqual($translation_service
      ->getTargetStatus($this->node, 'ES'), Lingotek::STATUS_UNTRACKED);
  }
  
  public function testRequestTranslationWithADocumentArchivedError() {
    \Drupal::state()
      ->set('lingotek.must_document_archived_error_in_request_translation', TRUE);
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool';
    $edit['body[0][value]'] = 'Llamas are very cool';
    $edit['langcode[0][value]'] = 'en';
    $edit['lingotek_translation_management[lingotek_translation_profile]'] = 'manual';
    $this
      ->saveAndPublishNodeForm($edit);
    
    $this
      ->drupalGet('node/1');
    $this
      ->clickLink('Translate');
    
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('Uploaded 1 document to Lingotek.');
    
    $this
      ->clickLink('Check Upload Status');
    $this
      ->assertText('The import for node Llamas are cool is complete.');
    
    $this
      ->clickLink('Request translation');
    $this
      ->assertText('Document node Llamas are cool has been archived. Please upload again.');
    $this->node = Node::load(1);
    
    $translation_service = \Drupal::service('lingotek.content_translation');
    $source_status = $translation_service
      ->getSourceStatus($this->node);
    $this
      ->assertEqual($source_status, Lingotek::STATUS_UNTRACKED);
    $this
      ->assertEqual($translation_service
      ->getTargetStatus($this->node, 'ES'), Lingotek::STATUS_UNTRACKED);
  }
  
  public function testRequestTranslationWithADocumentLockedError() {
    \Drupal::state()
      ->set('lingotek.must_document_locked_error_in_request_translation', TRUE);
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool';
    $edit['body[0][value]'] = 'Llamas are very cool';
    $edit['langcode[0][value]'] = 'en';
    $edit['lingotek_translation_management[lingotek_translation_profile]'] = 'manual';
    $this
      ->saveAndPublishNodeForm($edit);
    
    $this
      ->drupalGet('node/1');
    $this
      ->clickLink('Translate');
    
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertText('Uploaded 1 document to Lingotek.');
    
    $this
      ->clickLink('Check Upload Status');
    $this
      ->assertText('The import for node Llamas are cool is complete.');
    
    $this
      ->clickLink('Request translation');
    $this
      ->assertText('Document node Llamas are cool has a new version. The document id has been updated for all future interactions. Please try again.');
    $this->node = Node::load(1);
    
    $translation_service = \Drupal::service('lingotek.content_translation');
    $source_status = $translation_service
      ->getSourceStatus($this->node);
    $this
      ->assertEqual($source_status, Lingotek::STATUS_CURRENT);
    $this
      ->assertEqual($translation_service
      ->getTargetStatus($this->node, 'ES'), Lingotek::STATUS_UNTRACKED);
  }
  
  public function testDownloadingInvalidRevision() {
    
    \Drupal::state()
      ->set('lingotek.uploaded_content_type', 'node+invalidrevision');
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool';
    $edit['body[0][value]'] = 'Llamas are very cool';
    $edit['langcode[0][value]'] = 'en';
    $edit['lingotek_translation_management[lingotek_translation_profile]'] = 'automatic';
    $this
      ->saveAndPublishNodeForm($edit);
    
    $this
      ->clickLink('Translate');
    $this
      ->clickLink('Check Upload Status');
    $this
      ->assertText('The import for node Llamas are cool is complete.');
    
    $this
      ->clickLink('Request translation');
    
    $url = Url::fromRoute('lingotek.notify', [], [
      'query' => [
        'project_id' => 'test_project',
        'document_id' => 'dummy-document-hash-id',
        'locale_code' => 'es-MX',
        'locale' => 'es_MX',
        'complete' => 'true',
        'type' => 'target',
        'progress' => '100',
      ],
    ])
      ->setAbsolute()
      ->toString();
    $request = $this->client
      ->post($url, [
      'cookies' => $this->cookies,
      'headers' => [
        'Accept' => 'application/json',
        'Content-Type' => 'application/json',
      ],
      'http_errors' => FALSE,
    ]);
    $response = json_decode($request
      ->getBody(), TRUE);
    $this
      ->assertTrue($response['result']['download'], 'Spanish language has been downloaded after notification automatically.');
    $this
      ->assertEqual('Document downloaded.', $response['messages'][0]);
    $this
      ->drupalGet('node/1/translations');
    $this
      ->assertText('Las llamas son chulas');
  }
  
  public function testContentFormOperations() {
    
    $edit = [];
    $edit['title[0][value]'] = 'Llamas are cool';
    $edit['body[0][value]'] = 'Llamas are very cool';
    $edit['langcode[0][value]'] = 'en';
    $edit['lingotek_translation_management[lingotek_translation_profile]'] = 'manual';
    $this
      ->saveAndPublishNodeForm($edit);
    
    $this
      ->drupalGet('node/1');
    $this
      ->clickLink('Translate');
    
    $this
      ->assertSession()
      ->linkExists('Add');
    $this
      ->assertSession()
      ->linkByHrefExists('/es/node/1/translations/add/en/es');
    
    $this
      ->clickLink('Upload');
    $this
      ->checkForMetaRefresh();
    $this
      ->assertSession()
      ->pageTextContains('Uploaded 1 document to Lingotek.');
    
    $this
      ->assertSession()
      ->linkExists('Add');
    $this
      ->assertSession()
      ->linkByHrefExists('/es/node/1/translations/add/en/es');
    
    $this
      ->clickLink('Check Upload Status');
    $this
      ->assertSession()
      ->pageTextContains('The import for node Llamas are cool is complete.');
    
    $this
      ->assertSession()
      ->linkExists('Add');
    $this
      ->assertSession()
      ->linkByHrefExists('/es/node/1/translations/add/en/es');
    
    $this
      ->clickLink('Request translation');
    $this
      ->assertSession()
      ->pageTextContains("Locale 'es_MX' was added as a translation target for node Llamas are cool.");
    $this
      ->assertSame('es_MX', \Drupal::state()
      ->get('lingotek.added_target_locale'));
    
    $this
      ->assertSession()
      ->linkExists('Add');
    $this
      ->assertSession()
      ->linkByHrefExists('/es/node/1/translations/add/en/es');
    
    $this
      ->clickLink('Check translation status');
    $this
      ->assertSame('es_MX', \Drupal::state()
      ->get('lingotek.checked_target_locale'));
    $this
      ->assertSession()
      ->pageTextContains('The es_MX translation for node Llamas are cool is ready for download.');
    
    $this
      ->assertSession()
      ->linkExists('Add');
    $this
      ->assertSession()
      ->linkByHrefExists('/es/node/1/translations/add/en/es');
    $this
      ->assertSession()
      ->linkExistsExact('Edit in Lingotek Workbench');
    $this
      ->assertSession()
      ->linkByHrefExists('/admin/lingotek/workbench/dummy-document-hash-id/es_MX');
    
    $this
      ->clickLink('Download completed translation');
    $this
      ->assertSession()
      ->pageTextContains('The translation of node Llamas are cool into es_MX has been downloaded.');
    $this
      ->assertSame('es_MX', \Drupal::state()
      ->get('lingotek.downloaded_locale'));
    
    $this
      ->assertSession()
      ->linkExistsExact('Edit in Lingotek Workbench');
    $this
      ->assertSession()
      ->linkByHrefExists('/admin/lingotek/workbench/dummy-document-hash-id/es_MX');
    $this
      ->assertSession()
      ->linkExistsExact('Edit');
    $this
      ->assertSession()
      ->linkByHrefExists('/es/node/1/edit');
    
    $this
      ->clickLink('Las llamas son chulas');
    $this
      ->assertSession()
      ->pageTextContains('Las llamas son chulas');
    $this
      ->assertSession()
      ->pageTextContains('Las llamas son muy chulas');
  }
  protected function getDestination($entity_type_id = 'node', $prefix = NULL) {
    return '';
  }
}