Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UHF-10908 FunctionalJS test for cookie banner #861

Merged
merged 22 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
12030cd
Revert "UHF-10908: Reverted the changes for functional cookie banner …
khalima Dec 10, 2024
d068cc3
UHF-10908: Merge branch 'main' of https://github.com/City-of-Helsinki…
khalima Dec 10, 2024
2e4b7fd
UHF-10908: Merge branch 'main' of https://github.com/City-of-Helsinki…
khalima Dec 10, 2024
647498b
UHF-10908: Support for functional js tests
tuutti Dec 10, 2024
932cb5a
UHF-10908: Run as root
tuutti Dec 10, 2024
b30e98d
UHF-10908: Use updated test image
tuutti Dec 10, 2024
c27db4e
UHF-10908: Set user
tuutti Dec 10, 2024
3d92dc3
UHF-10908: Use ci images again
tuutti Dec 10, 2024
ce65b72
UHF-10908: Use local image again
tuutti Dec 10, 2024
e4089eb
UHF-10908: Test 8.3
tuutti Dec 10, 2024
b1cbe26
UHF-10908: Debug
tuutti Dec 10, 2024
dce37b2
UHF-10908: Empty commit to trigger test
tuutti Dec 10, 2024
632cbe9
UHF-10908: Override entrypoint
tuutti Dec 10, 2024
7a6774e
UHF-10908: Testing
tuutti Dec 10, 2024
098f5c6
UHF-10908: Install drupal after lint checks
tuutti Dec 11, 2024
b44c917
UHF-10908: Correct webroot
tuutti Dec 11, 2024
7839a69
UHF-10908: Fixed env variable
tuutti Dec 11, 2024
2e36014
Update CookieBannerTest.php
khalima Dec 12, 2024
a62b560
UHF-10908: Merge branch 'main' of https://github.com/City-of-Helsinki…
khalima Dec 12, 2024
146ff07
UHF-10908: Fixed translations for the views pager to prevent race con…
khalima Dec 12, 2024
17fd4ee
Revert "UHF-10908: Fixed translations for the views pager to prevent …
khalima Dec 12, 2024
aa91b08
UHF-10908: Reverted helfi_platform to main branch.
khalima Dec 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 35 additions & 19 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@ on:
name: CI
env:
SYMFONY_DEPRECATIONS_HELPER: disabled
SIMPLETEST_BASE_URL: http://app:8888
COMPOSER_DISCARD_CHANGES: true
COMPOSER_MIRROR_PATH_REPOS: 1
jobs:
tests:
runs-on: ubuntu-latest
strategy:
matrix:
php-versions: ['8.1', '8.2', '8.3']
php-versions: ['8.3']
container:
image: ghcr.io/city-of-helsinki/drupal-php-docker:${{ matrix.php-versions }}-alpine
options: --hostname app
image: ghcr.io/city-of-helsinki/drupal-web:${{ matrix.php-versions }}-dev
options: --hostname app --user 1001
services:
db:
image: mysql:8
Expand All @@ -26,6 +27,15 @@ jobs:
MYSQL_ROOT_PASSWORD: drupal
ports:
- 3306:3306
chromium:
image: selenium/standalone-chromium
env:
SE_NODE_OVERRIDE_MAX_SESSIONS: "true"
SE_NODE_MAX_SESSIONS: "16"
SE_START_XVFB: "false"
SE_START_VNC: "false"
SE_SESSION_RETRY_INTERVAL: "1"
SE_SESSION_REQUEST_TIMEOUT: "10"

steps:
- uses: actions/checkout@v4
Expand All @@ -38,6 +48,13 @@ jobs:
- name: Set Drupal root
run: echo "DRUPAL_ROOT=$HOME/drupal" >> $GITHUB_ENV

# Actions worker overrides the default entrypoint with "tail -f /dev/null", so
# we have to start services manually.
- name: Start services
env:
WEBROOT: ${{ env.DRUPAL_ROOT }}/public
run: entrypoint &

- name: Set module folder
run: |
echo "MODULE_FOLDER=$DRUPAL_ROOT/public/modules/contrib/$MODULE_NAME" >> $GITHUB_ENV
Expand All @@ -48,23 +65,17 @@ jobs:
git clone --depth=1 https://github.com/City-of-Helsinki/drupal-helfi-platform.git $DRUPAL_ROOT
rm -rf $DRUPAL_ROOT/.git

# We use COMPOSER_MIRROR_PATH_REPOS=1 to mirror local repository
# instead of symlinking it to prevent code coverage issues with
# phpunit. Copy .git folder manually so codecov can generate line by
# line coverage.
- name: Install required composer dependencies
working-directory: ${{ env.DRUPAL_ROOT }}
run: |
composer config repositories.5 path $GITHUB_WORKSPACE
composer require drupal/$MODULE_NAME -W
# We use COMPOSER_MIRROR_PATH_REPOS=1 to mirror local repository
# instead of symlinking it to prevent code coverage issues with
# phpunit. Copy .git folder manually so codecov can generate line by
# line coverage.
cp -r $GITHUB_WORKSPACE/.git $MODULE_FOLDER/

- name: Install Drupal
working-directory: ${{ env.DRUPAL_ROOT }}
run: |
php -d sendmail_path=$(which true); vendor/bin/drush --yes -v site-install minimal --db-url="$SIMPLETEST_DB"
vendor/bin/drush en $MODULE_NAME helfi_platform_config_base -y

- name: Run PHPCS
working-directory: ${{ env.DRUPAL_ROOT }}
run: vendor/bin/phpcs $MODULE_FOLDER --standard=$MODULE_FOLDER/phpcs.xml --extensions=php,module,inc,install,test,info
Expand All @@ -73,9 +84,11 @@ jobs:
working-directory: ${{ env.DRUPAL_ROOT }}
run: vendor/bin/phpstan analyze -c $MODULE_FOLDER/phpstan.neon $MODULE_FOLDER

- name: Start services
- name: Install Drupal
working-directory: ${{ env.DRUPAL_ROOT }}
run: vendor/bin/drush runserver $SIMPLETEST_BASE_URL --dns &
run: |
php -d sendmail_path=$(which true); vendor/bin/drush --yes -v site-install minimal --db-url="$SIMPLETEST_DB"
vendor/bin/drush en $MODULE_NAME helfi_platform_config_base -y

- name: Run PHPUnit tests
working-directory: ${{ env.DRUPAL_ROOT }}
Expand All @@ -86,9 +99,12 @@ jobs:
--coverage-clover=$MODULE_FOLDER/coverage.xml \
$MODULE_FOLDER

- name: Run codecov
working-directory: ${{ env.MODULE_FOLDER }}
run: codecov
- uses: codecov/codecov-action@v5
with:
fail_ci_if_error: true
directory: ${{ env.MODULE_FOLDER }}
token: ${{ secrets.CODECOV_TOKEN }}
verbose: true

- name: Create an artifact from test report
uses: actions/upload-artifact@v4
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name: 'HDBT cookie banner test module'
type: module
package: Custom
core_version_requirement: ^10 || ^11
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

/**
* @file
* Contains hooks for hdbt cookie banner test module.
*/

declare(strict_types=1);

/**
* Implements hook_page_attachments().
*/
function hdbt_cookie_banner_test_page_attachments(array &$attachments) : void {
// Alter the HDBT cookie banner settings.
$attachments['#attached']['drupalSettings']['hdbt_cookie_banner']['spacerParentSelector'] = '.test-footer';
global $base_url;
$attachments['#attached']['drupalSettings']['hdbt_cookie_banner']['apiUrl'] = $base_url . '/api/cookie-banner';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
hdbt_cookie_banner_test.test_route:
path: '/test-page'
defaults:
_controller: '\Drupal\hdbt_cookie_banner_test\Controller\TestController::content'
_title: 'Test Page'
requirements:
_permission: 'access content'
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Drupal\hdbt_cookie_banner_test\Controller;

use Drupal\Core\Controller\ControllerBase;

/**
* Provides a test page for the custom module.
*/
class TestController extends ControllerBase {

/**
* Test page content.
*
* @return array
* Render array.
*/
public function content() {
return [
'#type' => 'inline_template',
'#template' => '<p>Test Content</p><div class="test-footer"></div>',
];
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
<?php

namespace Drupal\Tests\hdbt_cookie_banner\FunctionalJavascript;

use Behat\Mink\Driver\Selenium2Driver;
use Drupal\FunctionalJavascriptTests\WebDriverTestBase;

/**
* Tests the functionality of the JavaScript cookie banner.
*
* @group hdbt_cookie_banner
*/
class CookieBannerTest extends WebDriverTestBase {

/**
* {@inheritdoc}
*/
protected static $modules = [
'hdbt_cookie_banner',
'hdbt_cookie_banner_test',
];

/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';

/**
* Setup the test environment.
*/
protected function setUp(): void {
parent::setUp();

// Get the path to the JSON file.
$module_path = \Drupal::service('extension.list.module')
->getPath('hdbt_cookie_banner');
$json_file_path = $module_path . '/assets/json/siteSettingsTemplate.json';

// Assert the file exists.
$this->assertTrue(file_exists($json_file_path));

// Load and decode the JSON.
$json_content = file_get_contents($json_file_path);
$this->assertNotEmpty($json_content, 'Decoded JSON data is not empty.');

// Get the public base URL (in a FunctionalJavascript test).
// Construct a URL for the hds-cookie-consent.min.js file.
$cookie_js_url = "/$module_path/assets/js/hds-cookie-consent.min.js";

// Change configuration value before the test runs.
$config = $this->config('hdbt_cookie_banner.settings');
$config
->set('use_custom_settings', TRUE)
->set('site_settings', $json_content)
->set('use_internal_hds_cookie_js', FALSE)
->set('hds_cookie_js_override', $cookie_js_url)
->save();

\Drupal::service('cache.default')->deleteAll();
}

/**
* Tests the cookie banner visibility and interaction.
*/
public function testCookieBanner() {
$this->drupalGet('/test-page');
$this->assertSession()->pageTextContains('Test Content');
$this->assertSession()->elementExists('css', '.test-footer');

// Get the web driver.
$driver = $this->getSession()->getDriver();

// Check if the driver is an instance of DrupalSelenium2Driver.
if ($driver instanceof Selenium2Driver) {
// Get all cookies from the browser.
$cookies = $driver->getWebDriverSession()->getCookie();

// Extract only the 'name' keys from all the cookies, as we want to check
// if a specific cookie "change-me" exists.
$cookieNames = array_column($cookies, 'name');
$this->assertNotContains(
'change-me',
$cookieNames,
'The cookie "change-me" was found, but it should not exist.',
);
}
else {
$this->fail('The driver is not an instance of Selenium2Driver.');
}

// Assert that the cookie banner is visible and click the accept button.
$this->assertCookieBannerIsVisible();

// Get the new cookies from the browser.
$new_cookies = $driver->getWebDriverSession()->getCookie();

// There should be a new cookie called "change-me".
$cookieNames = array_column($new_cookies, 'name');
$this->assertContains(
'change-me',
$cookieNames,
'The cookie "change-me" was not found after clicking the button.',
);

// Reload the page and assert that the cookie banner is not visible.
$this->drupalGet('/test-page');
$this->assertSession()->pageTextContains('Test Content');
$this->assertCookieBannerNotVisible();
}

/**
* Asserts that the cookie banner is visible.
*/
protected function assertCookieBannerIsVisible() {
// Get the Shadow DOM host and button selectors.
$shadowHostSelector = '.hds-cc__target';
$buttonSelector = '.hds-cc__all-cookies-button';

// Verify that the cookie banner is visible and click the accept button.
$js = <<<JS
const shadowHost = document.querySelector('$shadowHostSelector');
if (!shadowHost) {
throw new Error('Shadow host not found.');
}
const shadowRoot = shadowHost.shadowRoot;
if (!shadowRoot) {
throw new Error('Shadow root is not attached.');
}
const button = shadowRoot.querySelector('$buttonSelector');
if (!button) {
throw new Error('Button not found inside the shadow DOM.');
}
button.click();
JS;

// Execute the JavaScript in the browser context.
$this->getSession()->executeScript($js);
}

/**
* Asserts that the cookie banner is not visible.
*/
protected function assertCookieBannerNotVisible() {
// Get the Shadow DOM host and button selectors.
$shadowHostSelector = '.hds-cc__target';

// Verify that the cookie banner is not visible.
$js = <<<JS
const shadowHost = document.querySelector('$shadowHostSelector');
if (shadowHost) {
throw new Error('Shadow host still found.');
}
JS;
// Execute the JavaScript in the browser context.
$this->getSession()->executeScript($js);
}

}
7 changes: 3 additions & 4 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@
<ini name="error_reporting" value="32767"/>
<!-- Do not limit the amount of memory tests take to run. -->
<ini name="memory_limit" value="-1"/>
<env name="MINK_DRIVER_ARGS_WEBDRIVER" value='["chrome", {"browserName":"chrome","chromeOptions":{"w3c": false, "args":["--disable-gpu","--headless", "--no-sandbox"]}}, "http://127.0.0.1:4444"]' />
<env name="DTT_MINK_DRIVER_ARGS" value='["chrome", {"chromeOptions":{"w3c": false }}, "http://chromium:4444"]'/>
<env name="DTT_API_OPTIONS" value='{"socketTimeout": 360, "domWaitTimeout": 3600000}' />
<env name="MINK_DRIVER_ARGS_WEBDRIVER" value='["chrome", {"browserName":"chrome", "goog:chromeOptions":{"w3c": true, "args":["--no-sandbox", "--ignore-certificate-errors", "--allow-insecure-localhost", "--headless", "--dns-prefetch-disable"]}}, "http://chromium:4444"]' />
<env name="DTT_MINK_DRIVER_ARGS" value='["chrome", {"browserName":"chrome", "goog:chromeOptions":{"w3c": true, "args":["--no-sandbox","--ignore-certificate-errors", "--allow-insecure-localhost", "--headless", "--dns-prefetch-disable"]}}, "http://chromium:4444"]'/> <env name="DTT_API_OPTIONS" value='{"socketTimeout": 360, "domWaitTimeout": 3600000}' />
<env name="DTT_API_URL" value="http://chromium:9222"/>
<env name="DTT_BASE_URL" value="http://app:8888"/>
<env name="DTT_BASE_URL" value="https://app"/>
</php>
<testsuites>
<testsuite name="unit">
Expand Down
Loading