/** * Tests configuration events. */ function testConfigEvents() { $name = 'config_events_test.test'; $config = new Config($name, \Drupal::service('config.storage'), \Drupal::service('event_dispatcher'), \Drupal::service('config.typed')); $config->set('key', 'initial'); \Drupal::state()->get('config_events_test.event', FALSE); $this->assertIdentical(\Drupal::state()->get('config_events_test.event', array()), array(), 'No events fired by creating a new configuration object'); $config->save(); $event = \Drupal::state()->get('config_events_test.event', array()); $this->assertIdentical($event['event_name'], ConfigEvents::SAVE); $this->assertIdentical($event['current_config_data'], array('key' => 'initial')); $this->assertIdentical($event['raw_config_data'], array('key' => 'initial')); $this->assertIdentical($event['original_config_data'], array()); $config->set('key', 'updated')->save(); $event = \Drupal::state()->get('config_events_test.event', array()); $this->assertIdentical($event['event_name'], ConfigEvents::SAVE); $this->assertIdentical($event['current_config_data'], array('key' => 'updated')); $this->assertIdentical($event['raw_config_data'], array('key' => 'updated')); $this->assertIdentical($event['original_config_data'], array('key' => 'initial')); $config->delete(); $event = \Drupal::state()->get('config_events_test.event', array()); $this->assertIdentical($event['event_name'], ConfigEvents::DELETE); $this->assertIdentical($event['current_config_data'], array()); $this->assertIdentical($event['raw_config_data'], array()); $this->assertIdentical($event['original_config_data'], array('key' => 'updated')); }
/** * Create an example node, test block through admin and user interfaces. */ public function testCronExampleBasic() { // Pretend that cron has never been run (even though simpletest seems to // run it once...) $this->cronConfig->set('cron_example_next_execution', 0); $this->drupalGet('examples/cron_example'); // Initial run should cause cron_example_cron() to fire. $post = []; $this->drupalPostForm('examples/cron_example', $post, t('Run cron now')); $this->assertText(t('cron_example executed at')); // Forcing should also cause cron_example_cron() to fire. $post['cron_reset'] = TRUE; $this->drupalPostForm(NULL, $post, t('Run cron now')); $this->assertText(t('cron_example executed at')); // But if followed immediately and not forced, it should not fire. $post['cron_reset'] = FALSE; $this->drupalPostForm(NULL, $post, t('Run cron now')); $this->assertNoText(t('cron_example executed at')); $this->assertText(t('There are currently 0 items in queue 1 and 0 items in queue 2')); $post = ['num_items' => 5, 'queue' => 'cron_example_queue_1']; $this->drupalPostForm(NULL, $post, t('Add jobs to queue')); $this->assertText('There are currently 5 items in queue 1 and 0 items in queue 2'); $post = ['num_items' => 100, 'queue' => 'cron_example_queue_2']; $this->drupalPostForm(NULL, $post, t('Add jobs to queue')); $this->assertText('There are currently 5 items in queue 1 and 100 items in queue 2'); $post = []; $this->drupalPostForm('examples/cron_example', $post, t('Run cron now')); $this->assertPattern('/Queue 1 worker processed item with sequence 5 /'); $this->assertPattern('/Queue 2 worker processed item with sequence 100 /'); }
/** * {@inheritdoc} */ public function import(Row $row, array $old_destination_id_values = array()) { foreach ($row->getRawDestination() as $key => $value) { if (isset($value) || !empty($this->configuration['store null'])) { $this->config->set(str_replace(Row::PROPERTY_SEPARATOR, '.', $key), $value); } } $this->config->save(); return [$this->config->getName()]; }
/** * {@inheritdoc} */ public function import(Row $row, array $old_destination_id_values = array()) { if ($row->hasDestinationProperty('langcode')) { $this->config = $this->language_manager->getLanguageConfigOverride($row->getDestinationProperty('langcode'), $this->config->getName()); } foreach ($row->getRawDestination() as $key => $value) { if (isset($value) || !empty($this->configuration['store null'])) { $this->config->set(str_replace(Row::PROPERTY_SEPARATOR, '.', $key), $value); } } $this->config->save(); return [$this->config->getName()]; }
/** * @covers ::delete * @dataProvider overrideDataProvider */ public function testDelete($data, $module_data) { $this->cacheTagsInvalidator->expects($this->once())->method('invalidateTags')->with(['config:config.test']); // Set initial data. foreach ($data as $key => $value) { $this->config->set($key, $value); } // Set overrides. $this->config->setModuleOverride($module_data); // Save. $this->config->save(); // Check that original data is still correct. $this->assertOriginalConfigDataEquals($data, FALSE); // Check overrides have been set. $this->assertConfigDataEquals($module_data); $this->assertOriginalConfigDataEquals($module_data, TRUE); // Check that config is new. $this->assertFalse($this->config->isNew()); // Delete. $this->config->delete(); // Check object properties have been reset. $this->assertTrue($this->config->isNew()); foreach ($data as $key => $value) { $this->assertEmpty($this->config->getOriginal($key, FALSE)); } // Check that overrides have persisted. foreach ($module_data as $key => $value) { $this->assertConfigDataEquals($module_data); $this->assertOriginalConfigDataEquals($module_data, TRUE); } }
/** * Tags should differ between languages and from generic tags. */ public function testTagUnicity() { // Enable some languages first. $this->config->set('language.php.enabled', TRUE); $this->config->set('language.python.enabled', TRUE); // First round: without format specific tag options. $this->config->set('use_format_specific_options', FALSE); $this->config->set('tags', 'code blockcode generictag'); $this->config->save(); // A language tag should differ from the generic tags. $form_values = array('language[php][tags]' => 'php generictag'); $this->drupalPostForm('admin/config/content/formats/geshifilter/languages/all', $form_values, t('Save configuration')); $this->assertText(t('The language tags should differ between languages and from the generic tags.'), t('Language tags should differ from generic tags (with generic tag options)')); // Language tags should differ between languages. $form_values = array('language[php][tags]' => 'php languagetag', 'language[python][tags]' => 'languagetag python'); $this->drupalPostForm('admin/config/content/formats/geshifilter/languages/all', $form_values, t('Save configuration')); $this->assertText(t('The language tags should differ between languages and from the generic tags.'), t('Language tags should differ between languages (with generic tag options)')); // Second round: with format specific tag options. // $this->config->set('use_format_specific_options', TRUE); // $this->drupalPostForm('admin/config/content/formats/manage/geshifilter_text_format', array(),t('Save configuration')); /*$this->config->set('tags_' . $this->input_format_id, 'code blockcode generictag'); // A language tag should differ from the generic tags. $form_values = array( 'geshifilter_language_tags_php_' . $this->input_format_id => 'php generictag'); $this->drupalPostForm('admin/config/content/formats/' . $this->input_format_id . '/configure', $form_values, t('Save configuration')); $this->assertText(t('The language tags should differ between languages and from the generic tags.'), t('Language tags should differ from (with format specific tag options)')); // Language tags should differ between languages. $form_values = array( 'geshifilter_language_tags_php_' . $this->input_format_id => 'php languagetag', 'geshifilter_language_tags_python_' . $this->input_format_id => 'languagetag python', ); $this->drupalPostForm('admin/config/content/formats/' . $this->input_format_id . '/configure', $form_values, t('Save configuration')); $this->assertText(t('The language tags should differ between languages and from the generic tags.'), t('Language tags should differ between languages (with format specific tag options)'));*/ }
/** * Set up the tests and create the users. */ public function setUp() { parent::setUp(); // Create object with configuration. $this->config = \Drupal::configFactory()->getEditable('geshifilter.settings'); // And set the path to the geshi library. $this->config->set('geshi_dir', '/libraries/geshi'); $settings = array('type' => 'geshifilter_content_type', 'name' => 'Geshifilter Content'); $this->drupalCreateContentType($settings); // Create a filter admin user. $permissions = array('administer filters', 'access administration pages', 'administer site configuration'); $this->filterAdminUser = $this->drupalCreateUser($permissions); // Log in with filter admin user. $this->drupalLogin($this->filterAdminUser); // Add an text format with only geshi filter. $this->createTextFormat('geshifilter_text_format', array('filter_geshifilter')); }
/** * Will test the redirects. */ public function testRedirects() { // Test alias normalization. $this->config->set('normalize_aliases', TRUE)->save(); $this->assertRedirect('node/' . $this->node->id(), 'test-node'); $this->assertRedirect('Test-node', 'test-node'); $this->config->set('normalize_aliases', FALSE)->save(); $this->assertRedirect('node/' . $this->node->id(), NULL, 'HTTP/1.1 200 OK'); $this->assertRedirect('Test-node', NULL, 'HTTP/1.1 200 OK'); // Test deslashing. $this->config->set('deslash', TRUE)->save(); $this->assertRedirect('test-node/', 'test-node'); $this->config->set('deslash', FALSE)->save(); $this->assertRedirect('test-node/', NULL, 'HTTP/1.1 200 OK'); // Test front page redirects. $this->config->set('frontpage_redirect', TRUE)->save(); $this->config('system.site')->set('page.front', '/node')->save(); $this->assertRedirect('node', '<front>'); // Test front page redirects with an alias. \Drupal::service('path.alias_storage')->save('/node', '/node-alias'); $this->assertRedirect('node-alias', '<front>'); $this->config->set('frontpage_redirect', FALSE)->save(); $this->assertRedirect('node', NULL, 'HTTP/1.1 200 OK'); $this->assertRedirect('node-alias', NULL, 'HTTP/1.1 200 OK'); // Test post request. $this->config->set('normalize_aliases', TRUE)->save(); $this->drupalPost('Test-node', 'application/json', array()); // Does not do a redirect, stays in the same path. $this->assertEqual(basename($this->getUrl()), 'Test-node'); // Test the access checking. $this->config->set('normalize_aliases', TRUE)->save(); $this->config->set('access_check', TRUE)->save(); $this->assertRedirect('admin/config/system/site-information', NULL, 'HTTP/1.1 403 Forbidden'); $this->config->set('access_check', FALSE)->save(); // @todo - here it seems that the access check runs prior to our redirecting // check why so and enable the test. //$this->assertRedirect('admin/config/system/site-information', 'site-info'); // Login as user with admin privileges. $this->drupalLogin($this->adminUser); // Test ignoring admin paths. $this->config->set('ignore_admin_path', FALSE)->save(); $this->assertRedirect('admin/config/system/site-information', 'site-info'); $this->config->set('ignore_admin_path', TRUE)->save(); $this->assertRedirect('admin/config/system/site-information', NULL, 'HTTP/1.1 200 OK'); }
/** * Implements Mollom::saveConfiguration(). */ public function saveConfiguration($name, $value) { // Save it to the class properties if applicable. if (property_exists('\\Drupal\\mollom\\API\\DrupalClient', $name)) { $this->{$name} = $value; } // Persist in Drupal too. $name = $this->configuration_map[$name]; $this->config->set($name, $value)->save(); }
/** * Marks the check as skipped. It still can be ran manually, but will remain * skipped on the Run & Review page. */ public function skip() { if (!$this->isSkipped()) { $this->config->set('skipped', TRUE); $this->config->set('skipped_by', Drupal::currentUser()->id()); $this->config->set('skipped_on', time()); $this->config->save(); // Log. $context = array('!name' => $this->getTitle()); SecurityReview::log($this, '!name check skipped', $context, RfcLogLevel::NOTICE); } }
/** * {@inheritdoc} */ public function batchVariableSet(array $variables) { $state_variables = xmlsitemap_state_variables(); $config_variables = xmlsitemap_config_variables(); foreach ($variables as $variable => $value) { if (isset($state_variables[$variable])) { $this->state->set($variable, $value); } else { $this->config->set($variable, $value); } } $this->config->save(); }
protected function assertFlag($variable, $assert_value = TRUE, $reset_if_true = TRUE) { $value = xmlsitemap_var($variable); if ($reset_if_true && $value) { $state_variables = xmlsitemap_state_variables(); if (isset($state_variables[$variable])) { $this->state->set($variable, FALSE); } else { $this->config->set($variable, FALSE)->save(); } } return $this->assertEqual($value, $assert_value, "xmlsitemap_{$variable} is " . ($assert_value ? 'TRUE' : 'FALSE')); }
/** * Tests the mail theme. */ public function testMailTheme() { // Mail System uses its own configuration for the used mail plugins. // Use the mail collector just like WebTestBase::initConfig(). $this->config->set('defaults.sender', 'test_mail_collector')->set('defaults.formatter', 'test_mail_collector')->save(); // Send an email with the default setting (should NOT use the test theme). $this->drupalGet('/mailsystem-test/theme'); $mails = $this->drupalGetMails(); // Check the configuration and if the correct theme was used in mails. $this->assertEqual($this->config->get('theme'), 'current'); $this->assertTrue(strpos($mails[0]['body'], 'Anonymous (not verified)') !== FALSE); // Install the test theme and set it as the mail theme. \Drupal::service('theme_handler')->install(array('mailsystem_test_theme')); $this->config->set('theme', 'mailsystem_test_theme')->save(); // Send another email (now it should use the test theme). $this->drupalGet('/mailsystem-test/theme'); $mails = $this->drupalGetMails(); // Check the new configuration and ensure that our test theme and its // implementation of the username template are used in mails. $this->assertEqual($this->config->get('theme'), 'mailsystem_test_theme'); $this->assertTrue(strpos($mails[1]['body'], 'Mailsystem test theme') !== FALSE); }
/** * Issue https://www.drupal.org/node/2047021. */ public function testSpecialChars() { $this->config->set('tags', 'code'); $this->config->set('language.php.enabled', TRUE); $this->config->set('decode_entities', TRUE); $this->config->save(); $source = '<code language="php"><?php echo("<b>Hi</b>"); ?></code>'; // Create a node. $node = array('title' => 'Test for Custom Filter', 'body' => array(array('value' => $source, 'format' => 'geshifilter_text_format')), 'type' => 'geshifilter_content_type'); $this->drupalCreateNode($node); $this->drupalGet('node/1'); // The same string must be on page, not double encoded. $this->assertRaw('"<b>Hi</b>"', 'The code is not double encoded.'); }
/** * {@inheritdoc} */ public function removeNodeFromList($param) { if ($param instanceof NodeInterface) { $param = $param->id(); } if (!is_numeric($param)) { return FALSE; } $exclude_list = $this->getExcludedNodes(); if (($key = array_search($param, $exclude_list)) !== FALSE) { unset($exclude_list[$key]); $this->settingsConfig->set('nid_list', $exclude_list)->save(); } return $this; }
/** * @covers ::setData * @covers ::set * @covers ::initWithData */ public function testSafeStringHandling() { // Safe strings are cast when using ::set(). $safe_string = Markup::create('bar'); $this->config->set('foo', $safe_string); $this->assertSame('bar', $this->config->get('foo')); $this->config->set('foo', ['bar' => $safe_string]); $this->assertSame('bar', $this->config->get('foo.bar')); // Safe strings are cast when using ::setData(). $this->config->setData(['bar' => $safe_string]); $this->assertSame('bar', $this->config->get('bar')); // Safe strings are not cast when using ::initWithData(). $this->config->initWithData(['bar' => $safe_string]); $this->assertSame($safe_string, $this->config->get('bar')); }
/** * Set config for theme settings, core seems to have forgotten themes can * have custom settings that you probably very much need in config. */ public function settingsConvertToConfig(array $values, Config $config) { foreach ($values as $key => $value) { // Save settings as config if (substr($key, 0, 9) == 'settings_') { $config_key = Unicode::substr($key, 9); $config->set('settings.' . $config_key, $value)->save(); } // Delete suggestions config settings. We do not remove all the suggestions settings // because later on if the suggestion is recreated there will be settings for it already, // which is kind of nice for the user should they accidentally delete a suggestion. if (substr($key, 0, 18) == 'delete_suggestion_') { $delete_suggestion_key = 'settings.suggestion_' . Unicode::substr($key, 18); if ($value == 1) { $config->clear($delete_suggestion_key, $value)->save(); } } } }
/** * {@inheritdoc} */ public function submitForm(array &$form, FormStateInterface $form_state) { $configurable_types = $form['#language_types']; $stored_values = $this->languageTypes->get('configurable'); $customized = array(); $method_weights_type = array(); foreach ($configurable_types as $type) { $customized[$type] = in_array($type, $stored_values); $method_weights = array(); $enabled_methods = $form_state->getValue(array($type, 'enabled')); $enabled_methods[LanguageNegotiationSelected::METHOD_ID] = TRUE; $method_weights_input = $form_state->getValue(array($type, 'weight')); if ($form_state->hasValue(array($type, 'configurable'))) { $customized[$type] = !$form_state->isValueEmpty(array($type, 'configurable')); } foreach ($method_weights_input as $method_id => $weight) { if ($enabled_methods[$method_id]) { $method_weights[$method_id] = $weight; } } $method_weights_type[$type] = $method_weights; $this->languageTypes->set('negotiation.' . $type . '.method_weights', $method_weights_input)->save(); } // Update non-configurable language types and the related language // negotiation configuration. $this->negotiator->updateConfiguration(array_keys(array_filter($customized))); // Update the language negotiations after setting the configurability. foreach ($method_weights_type as $type => $method_weights) { $this->negotiator->saveConfiguration($type, $method_weights); } // Clear block definitions cache since the available blocks and their names // may have been changed based on the configurable types. if ($this->blockStorage) { // If there is an active language switcher for a language type that has // been made not configurable, deactivate it first. $non_configurable = array_keys(array_diff($customized, array_filter($customized))); $this->disableLanguageSwitcher($non_configurable); } $this->blockManager->clearCachedDefinitions(); $form_state->setRedirect('language.negotiation'); drupal_set_message($this->t('Language detection configuration saved.')); }
/** * Code run before each and every test method. */ public function setUp() { parent::setUp(); // Create object with configuration. $this->config = \Drupal::configFactory()->getEditable('geshifilter.settings'); // And set the path to the geshi library. $this->config->set('geshi_dir', '/libraries/geshi'); // Create a content type, as we will create nodes on test. $settings = array('type' => 'geshifilter_content_type', 'name' => 'Geshifilter Content'); $this->drupalCreateContentType($settings); $this->adminUser = $this->drupalCreateUser(array(), NULL, TRUE); // Log in with filter admin user. $this->drupalLogin($this->adminUser); // Add an text format with only geshi filter. $this->createTextFormat('geshifilter_text_format', array('filter_geshifilter')); // Set some default GeSHi filter admin settings. // Set default highlighting mode to "do nothing". $this->config->set('default_highlighting', GeshiFilter::DEFAULT_PLAINTEXT); $this->config->set('use_format_specific_options', FALSE); $this->config->set('tag_styles', array(GeshiFilter::BRACKETS_ANGLE => GeshiFilter::BRACKETS_ANGLE, GeshiFilter::BRACKETS_SQUARE => GeshiFilter::BRACKETS_SQUARE)); $this->config->set('default_line_numbering', GeshiFilter::LINE_NUMBERS_DEFAULT_NONE); $this->config->save(); }
/** * Creates configuration in a collection based on the provided list. * * @param string $collection * The configuration collection. * @param array $config_to_create * An array of configuration data to create, keyed by name. */ protected function createConfiguration($collection, array $config_to_create) { // Order the configuration to install in the order of dependencies. if ($collection == StorageInterface::DEFAULT_COLLECTION) { $dependency_manager = new ConfigDependencyManager(); $config_names = $dependency_manager->setData($config_to_create)->sortAll(); } else { $config_names = array_keys($config_to_create); } foreach ($config_names as $name) { // Allow config factory overriders to use a custom configuration object if // they are responsible for the collection. $overrider = $this->configManager->getConfigCollectionInfo()->getOverrideService($collection); if ($overrider) { $new_config = $overrider->createConfigObject($name, $collection); } else { $new_config = new Config($name, $this->getActiveStorages($collection), $this->eventDispatcher, $this->typedConfig); } if ($config_to_create[$name] !== FALSE) { $new_config->setData($config_to_create[$name]); // Add a hash to configuration created through the installer so it is // possible to know if the configuration was created by installing an // extension and to track which version of the default config was used. if (!$this->isSyncing() && $collection == StorageInterface::DEFAULT_COLLECTION) { $new_config->set('_core.default_config_hash', Crypt::hashBase64(serialize($config_to_create[$name]))); } } if ($collection == StorageInterface::DEFAULT_COLLECTION && ($entity_type = $this->configManager->getEntityTypeIdByName($name))) { // If we are syncing do not create configuration entities. Pluggable // configuration entities can have dependencies on modules that are // not yet enabled. This approach means that any code that expects // default configuration entities to exist will be unstable after the // module has been enabled and before the config entity has been // imported. if ($this->isSyncing()) { continue; } /** @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface $entity_storage */ $entity_storage = $this->configManager->getEntityManager()->getStorage($entity_type); // It is possible that secondary writes can occur during configuration // creation. Updates of such configuration are allowed. if ($this->getActiveStorages($collection)->exists($name)) { $id = $entity_storage->getIDFromConfigName($name, $entity_storage->getEntityType()->getConfigPrefix()); $entity = $entity_storage->load($id); $entity = $entity_storage->updateFromStorageRecord($entity, $new_config->get()); } else { $entity = $entity_storage->createFromStorageRecord($new_config->get()); } if ($entity->isInstallable()) { $entity->trustData()->save(); } } else { $new_config->save(TRUE); } } }
/** * Tests enabling and disabling of testing mode. */ function testTestingMode() { $this->drupalLogin($this->adminUser); // Protect mollom_test_form. $this->setProtectionUI('mollom_test_post_form', FormInterface::MOLLOM_MODE_ANALYSIS); $this->settings->set('fallback', FormInterface::MOLLOM_FALLBACK_ACCEPT)->save(); // Setup production API keys and expected languages. They must be retained. $publicKey = 'the-invalid-mollom-api-key-value'; $privateKey = 'the-invalid-mollom-api-key-value'; $expectedLanguages = ['en', 'de']; $edit = ['keys[public]' => $publicKey, 'keys[private]' => $privateKey, 'languages_expected[]' => $expectedLanguages]; $this->drupalGet('admin/config/content/mollom/settings'); $this->assertText('The Mollom API keys are not configured yet.'); $this->drupalPostForm(NULL, $edit, t('Save configuration'), ['watchdog' => RfcLogLevel::EMERGENCY]); $this->assertNoText('The Mollom API keys are not configured yet.'); $this->assertText(t('The configuration options have been saved.')); $this->assertText('The configured Mollom API keys are invalid.'); $this->drupalLogout(); // Verify that spam can be posted, since testing mode is disabled and API // keys are invalid. $edit = ['title' => $this->randomString(), 'body' => 'spam']; $this->drupalGet('mollom-test/form', ['watchdog' => RfcLogLevel::EMERGENCY]); $this->drupalPostForm(NULL, $edit, t('Save'), ['watchdog' => RfcLogLevel::EMERGENCY]); $this->assertText('Successful form submission.'); // Enable testing mode. $this->drupalLogin($this->adminUser); $edit = ['testing_mode' => TRUE]; $this->drupalGet('admin/config/content/mollom/settings', ['watchdog' => RfcLogLevel::EMERGENCY]); $this->assertText('The configured Mollom API keys are invalid.'); $this->drupalPostForm(NULL, $edit, t('Save configuration')); $this->assertNoText('The Mollom API keys are not configured yet.'); $this->assertNoText('The configured Mollom API keys are invalid.'); $this->assertText(t('Mollom testing mode is still enabled.')); // Verify that expected languages were retained. foreach ($expectedLanguages as $lang) { $this->assertOptionSelected('edit-languages-expected', $lang); } $this->drupalLogout(); // Verify presence of testing mode warning. $this->drupalGet('mollom-test/form'); /* * There is a problem with the way #lazy_builder is handling the status * messages in tests. As a result, the text is only output when a message * is set before it too.... further investigation is needed and possibly * a bug filed. $this->assertText(t('Mollom testing mode is still enabled.')); */ // Verify that no spam can be posted with testing mode enabled. $edit = ['title' => $this->randomString(), 'body' => 'spam']; $this->drupalPostForm(NULL, $edit, t('Save')); $this->assertText(self::SPAM_MESSAGE); $this->assertNoText('Successful form submission.'); // Disable testing mode. $this->drupalLogin($this->adminUser); $this->drupalGet('admin/config/content/mollom/settings'); $this->assertText('Mollom testing mode is still enabled.'); $edit = ['testing_mode' => FALSE]; $this->drupalPostForm(NULL, $edit, t('Save configuration'), ['watchdog' => RfcLogLevel::EMERGENCY]); $this->assertText(t('The configuration options have been saved.')); $this->assertText('The configured Mollom API keys are invalid.'); $this->assertNoText('Mollom testing mode is still enabled.'); // Verify that production API keys still exist. $this->assertFieldByName('keys[public]', $publicKey); $this->assertFieldByName('keys[private]', $privateKey); foreach ($expectedLanguages as $lang) { $this->assertOptionSelected('edit-languages-expected', $lang); } }
/** * {@inheritdoc} */ public function set($key, $value) { $this->config->set('settings.' . $key, $value); $this->config->save(); return $this; }