From 73e140118cd3a282b4f374c5644d4aedbdb03129 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 00:07:01 +1100 Subject: [PATCH 01/36] [#2394] Added Jest for JavaScript unit testing. --- .ahoy.yml | 7 +- .circleci/config.yml | 9 + .eslintrc.json | 10 + .github/workflows/build-test-deploy.yml | 9 + .../installer/src/Prompts/Handlers/Tools.php | 43 +- .../Handlers/ToolsHandlerProcessTest.php | 43 +- .../Handlers/ToolsHandlerDiscoveryTest.php | 22 +- AGENTS.md | 3 + jest.config.js | 26 + package.json | 5 +- web/modules/custom/ys_demo/js/ys_demo.js | 58 +- web/modules/custom/ys_demo/js/ys_demo.test.js | 270 +++ yarn.lock | 2061 ++++++++++++++++- 13 files changed, 2507 insertions(+), 59 deletions(-) create mode 100644 jest.config.js create mode 100644 web/modules/custom/ys_demo/js/ys_demo.test.js diff --git a/.ahoy.yml b/.ahoy.yml index facfca892..8638f2e2e 100644 --- a/.ahoy.yml +++ b/.ahoy.yml @@ -278,11 +278,16 @@ commands: cmd: ahoy cli vendor/bin/phpunit --testsuite=functional "$@" test-functional-javascript: - aliases: [test-js] usage: Run PHPUnit functional JavaScript tests. cmd: ahoy cli vendor/bin/phpunit --testsuite=functional-javascript "$@" #;> TOOL_PHPUNIT + #;< TOOL_JEST + test-js: + usage: Run Jest JavaScript unit tests. + cmd: ahoy cli "yarn test" + #;> TOOL_JEST + #;< TOOL_BEHAT test-bdd: usage: Run BDD tests. diff --git a/.circleci/config.yml b/.circleci/config.yml index f61d3dfb5..0675eb11e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -151,6 +151,9 @@ jobs: #;< TOOL_ESLINT_STYLELINT docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" #;> TOOL_ESLINT_STYLELINT + #;< TOOL_JEST + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" + #;> TOOL_JEST - run: name: Audit Composer packages @@ -200,6 +203,12 @@ jobs: command: docker compose exec -T cli bash -c "yarn run lint" || [ "${VORTEX_CI_NODEJS_LINT_IGNORE_FAILURE:-0}" -eq 1 ] #;> TOOL_ESLINT_STYLELINT + #;< TOOL_JEST + - run: + name: Test module code with Jest + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + #;> TOOL_JEST + #;< DRUPAL_THEME - run: name: Lint theme code with NodeJS linters diff --git a/.eslintrc.json b/.eslintrc.json index ef68a6a93..7208a7e8f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -61,6 +61,16 @@ "operator-linebreak": ["error", "after", { "overrides": { "?": "ignore", ":": "ignore" } }], "yml/indent": ["error", 2] }, + "overrides": [ + { + "files": ["*.test.js"], + "env": { "jest": true }, + "rules": { + "no-eval": "off", + "max-nested-callbacks": ["warn", 5] + } + } + ], "settings": { "jsdoc": { "tagNamePreference": { diff --git a/.github/workflows/build-test-deploy.yml b/.github/workflows/build-test-deploy.yml index e4cf98eb8..3a3670de5 100644 --- a/.github/workflows/build-test-deploy.yml +++ b/.github/workflows/build-test-deploy.yml @@ -134,6 +134,9 @@ jobs: #;< TOOL_ESLINT_STYLELINT docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" #;> TOOL_ESLINT_STYLELINT + #;< TOOL_JEST + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" + #;> TOOL_JEST - name: Audit Composer packages run: docker compose exec -T cli composer audit @@ -183,6 +186,12 @@ jobs: continue-on-error: ${{ vars.VORTEX_CI_NODEJS_LINT_IGNORE_FAILURE == '1' }} #;> TOOL_ESLINT_STYLELINT + #;< TOOL_JEST + - name: Test module code with Jest + run: docker compose exec -T cli bash -c "yarn test" + continue-on-error: ${{ vars.VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE == '1' }} + #;> TOOL_JEST + #;< DRUPAL_THEME - name: Lint theme code with NodeJS linters if: ${{ vars.VORTEX_FRONTEND_BUILD_SKIP != '1' }} diff --git a/.vortex/installer/src/Prompts/Handlers/Tools.php b/.vortex/installer/src/Prompts/Handlers/Tools.php index 5bafdfcc0..10c344ba7 100644 --- a/.vortex/installer/src/Prompts/Handlers/Tools.php +++ b/.vortex/installer/src/Prompts/Handlers/Tools.php @@ -30,6 +30,8 @@ class Tools extends AbstractHandler { const BEHAT = 'behat'; + const JEST = 'jest'; + /** * {@inheritdoc} */ @@ -62,6 +64,7 @@ public function default(array $responses): null|string|bool|array { return [ self::BEHAT, self::ESLINT, + self::JEST, self::PHPCS, self::PHPMD, self::PHPSTAN, @@ -111,10 +114,10 @@ public function process(): void { $this->processGroup($name); } - // Remove fei: command and its call when both FE lint tools and custom + // Remove fei: command and its call when all FE tools and custom // theme are absent, as there are no front-end dependencies to install. - $fe_group = $groups['frontend_linting'] ?? NULL; - if ($fe_group && isset($fe_group['tools']) && !array_intersect($fe_group['tools'], $selected_tools)) { + $fe_all_group = $groups['frontend_all'] ?? NULL; + if ($fe_all_group && isset($fe_all_group['tools']) && !array_intersect($fe_all_group['tools'], $selected_tools)) { $theme = $this->responses[Theme::id()] ?? NULL; if (in_array($theme, [Theme::OLIVERO, Theme::CLARO, Theme::STARK])) { File::replaceContentInFile($this->tmpDir . '/.ahoy.yml', Replacement::create('ahoy_fei', function (string $content): string { @@ -353,6 +356,27 @@ public static function getToolDefinitions(string $filter = 'all'): array { 'files' => ['.stylelintrc.js'], ], + self::JEST => [ + 'title' => 'Jest', + 'present' => fn(): mixed => File::contains($this->dstDir . '/package.json', '"jest":') || + File::exists($this->dstDir . '/jest.config.js'), + 'package.json' => function (JsonManipulator $pj): void { + $pj->removeSubNode('devDependencies', 'jest'); + $pj->removeSubNode('devDependencies', 'jest-environment-jsdom'); + $pj->removeSubNode('scripts', 'test'); + }, + 'files' => fn(): array => [ + $this->tmpDir . '/jest.config.js', + glob($this->tmpDir . '/' . $this->webroot . '/modules/custom/*/js/*.test.js'), + ], + 'lines' => [ + 'AGENTS.md' => [ + '# Jest testing', + 'ahoy test-js', + ], + ], + ], + self::PHPUNIT => [ 'title' => 'PHPUnit', 'present' => fn(): mixed => File::contains($this->dstDir . '/composer.json', 'phpunit/phpunit') || @@ -458,14 +482,23 @@ public static function getToolDefinitions(string $filter = 'all'): array { ], 'frontend_linting' => [ 'tools' => [self::ESLINT, self::STYLELINT], - 'files' => ['package.json', 'yarn.lock'], 'ahoy' => [ - '/^\h*ahoy cli "yarn install --frozen-lockfile"\h*\n?/m', '/^\h*ahoy cli "yarn run lint"\h*\n?/m', '/^\h*ahoy cli "yarn run lint-fix"\h*\n?/m', ], 'token' => 'TOOL_ESLINT_STYLELINT', ], + 'frontend_testing' => [ + 'tools' => [self::JEST], + 'token' => 'TOOL_JEST', + ], + 'frontend_all' => [ + 'tools' => [self::ESLINT, self::STYLELINT, self::JEST], + 'files' => ['package.json', 'yarn.lock'], + 'ahoy' => [ + '/^\h*ahoy cli "yarn install --frozen-lockfile"\h*\n?/m', + ], + ], ]; if ($filter === 'tools') { diff --git a/.vortex/installer/tests/Functional/Handlers/ToolsHandlerProcessTest.php b/.vortex/installer/tests/Functional/Handlers/ToolsHandlerProcessTest.php index 11afa358d..0b35e30e3 100644 --- a/.vortex/installer/tests/Functional/Handlers/ToolsHandlerProcessTest.php +++ b/.vortex/installer/tests/Functional/Handlers/ToolsHandlerProcessTest.php @@ -47,6 +47,7 @@ public static function dataProviderHandlerProcess(): \Iterator { $test->assertFileDoesNotExist(static::$sut . '/.prettierrc.json'); $test->assertFileDoesNotExist(static::$sut . '/.prettierignore'); $test->assertFileDoesNotExist(static::$sut . '/.stylelintrc.js'); + $test->assertFileDoesNotExist(static::$sut . '/jest.config.js'); $test->assertSutContains([ '/\blint-fe:/', @@ -335,10 +336,40 @@ public static function dataProviderHandlerProcess(): \Iterator { 'rector/rector', ])), ]; + yield 'tools_no_jest' => [ + static::cw(function (): void { + $tools = array_keys(Tools::getToolDefinitions('tools')); + Env::put(Tools::envName(), Converter::toList(array_diff($tools, [Tools::JEST]))); + Env::put(CiProvider::envName(), CiProvider::GITHUB_ACTIONS); + }), + static::cw(function (FunctionalTestCase $test): void { + $pj = static::$sut . '/package.json'; + $test->assertFileNotContainsString($pj, '"jest":'); + $test->assertFileNotContainsString($pj, '"jest-environment-jsdom":'); + $test->assertFileDoesNotExist(static::$sut . '/jest.config.js'); + $test->assertFileContainsString($pj, '"eslint":'); + $test->assertFileContainsString($pj, '"stylelint":'); + }), + ]; + yield 'tools_no_jest_circleci' => [ + static::cw(function (): void { + $tools = array_keys(Tools::getToolDefinitions('tools')); + Env::put(Tools::envName(), Converter::toList(array_diff($tools, [Tools::JEST]))); + Env::put(CiProvider::envName(), CiProvider::CIRCLECI); + }), + static::cw(function (FunctionalTestCase $test): void { + $pj = static::$sut . '/package.json'; + $test->assertFileNotContainsString($pj, '"jest":'); + $test->assertFileNotContainsString($pj, '"jest-environment-jsdom":'); + $test->assertFileDoesNotExist(static::$sut . '/jest.config.js'); + $test->assertFileContainsString($pj, '"eslint":'); + $test->assertFileContainsString($pj, '"stylelint":'); + }), + ]; yield 'tools_groups_no_fe_lint' => [ static::cw(function (): void { $tools = array_keys(Tools::getToolDefinitions('tools')); - Env::put(Tools::envName(), Converter::toList(array_diff($tools, [Tools::ESLINT, Tools::STYLELINT]))); + Env::put(Tools::envName(), Converter::toList(array_diff($tools, [Tools::ESLINT, Tools::STYLELINT, Tools::JEST]))); Env::put(CiProvider::envName(), CiProvider::GITHUB_ACTIONS); }), static::cw(function (FunctionalTestCase $test): void { @@ -349,12 +380,13 @@ public static function dataProviderHandlerProcess(): \Iterator { $test->assertFileDoesNotExist(static::$sut . '/.prettierrc.json'); $test->assertFileDoesNotExist(static::$sut . '/.prettierignore'); $test->assertFileDoesNotExist(static::$sut . '/.stylelintrc.js'); + $test->assertFileDoesNotExist(static::$sut . '/jest.config.js'); }), ]; yield 'tools_groups_no_fe_lint_circleci' => [ static::cw(function (): void { $tools = array_keys(Tools::getToolDefinitions('tools')); - Env::put(Tools::envName(), Converter::toList(array_diff($tools, [Tools::ESLINT, Tools::STYLELINT]))); + Env::put(Tools::envName(), Converter::toList(array_diff($tools, [Tools::ESLINT, Tools::STYLELINT, Tools::JEST]))); Env::put(CiProvider::envName(), CiProvider::CIRCLECI); }), static::cw(function (FunctionalTestCase $test): void { @@ -365,6 +397,7 @@ public static function dataProviderHandlerProcess(): \Iterator { $test->assertFileDoesNotExist(static::$sut . '/.prettierrc.json'); $test->assertFileDoesNotExist(static::$sut . '/.prettierignore'); $test->assertFileDoesNotExist(static::$sut . '/.stylelintrc.js'); + $test->assertFileDoesNotExist(static::$sut . '/jest.config.js'); }), ]; yield 'tools_groups_no_be_tests' => [ @@ -410,7 +443,7 @@ public static function dataProviderHandlerProcess(): \Iterator { yield 'tools_groups_no_fe_lint_no_theme' => [ static::cw(function (): void { $tools = array_keys(Tools::getToolDefinitions('tools')); - Env::put(Tools::envName(), Converter::toList(array_diff($tools, [Tools::ESLINT, Tools::STYLELINT]))); + Env::put(Tools::envName(), Converter::toList(array_diff($tools, [Tools::ESLINT, Tools::STYLELINT, Tools::JEST]))); Env::put(CiProvider::envName(), CiProvider::GITHUB_ACTIONS); Env::put(Theme::envName(), Theme::OLIVERO); }), @@ -422,6 +455,7 @@ public static function dataProviderHandlerProcess(): \Iterator { $test->assertFileDoesNotExist(static::$sut . '/.prettierrc.json'); $test->assertFileDoesNotExist(static::$sut . '/.prettierignore'); $test->assertFileDoesNotExist(static::$sut . '/.stylelintrc.js'); + $test->assertFileDoesNotExist(static::$sut . '/jest.config.js'); $test->assertSutNotContains([ 'yarn install', 'yarn run lint', @@ -433,7 +467,7 @@ public static function dataProviderHandlerProcess(): \Iterator { yield 'tools_groups_no_fe_lint_no_theme_circleci' => [ static::cw(function (): void { $tools = array_keys(Tools::getToolDefinitions('tools')); - Env::put(Tools::envName(), Converter::toList(array_diff($tools, [Tools::ESLINT, Tools::STYLELINT]))); + Env::put(Tools::envName(), Converter::toList(array_diff($tools, [Tools::ESLINT, Tools::STYLELINT, Tools::JEST]))); Env::put(CiProvider::envName(), CiProvider::CIRCLECI); Env::put(Theme::envName(), Theme::OLIVERO); }), @@ -445,6 +479,7 @@ public static function dataProviderHandlerProcess(): \Iterator { $test->assertFileDoesNotExist(static::$sut . '/.prettierrc.json'); $test->assertFileDoesNotExist(static::$sut . '/.prettierignore'); $test->assertFileDoesNotExist(static::$sut . '/.stylelintrc.js'); + $test->assertFileDoesNotExist(static::$sut . '/jest.config.js'); $test->assertSutNotContains([ 'yarn install', 'yarn run lint', diff --git a/.vortex/installer/tests/Unit/Handlers/ToolsHandlerDiscoveryTest.php b/.vortex/installer/tests/Unit/Handlers/ToolsHandlerDiscoveryTest.php index 61fd64b53..f450ba358 100644 --- a/.vortex/installer/tests/Unit/Handlers/ToolsHandlerDiscoveryTest.php +++ b/.vortex/installer/tests/Unit/Handlers/ToolsHandlerDiscoveryTest.php @@ -18,11 +18,11 @@ public static function dataProviderRunPrompts(): \Iterator { $expected_installed = static::getExpectedInstalled(); yield 'tools - prompt - defaults' => [ [Tools::id() => Key::ENTER], - [Tools::id() => [Tools::BEHAT, Tools::ESLINT, Tools::PHPCS, Tools::PHPMD, Tools::PHPSTAN, Tools::PHPUNIT, Tools::RECTOR, Tools::STYLELINT]] + $expected_defaults, + [Tools::id() => [Tools::BEHAT, Tools::ESLINT, Tools::JEST, Tools::PHPCS, Tools::PHPMD, Tools::PHPSTAN, Tools::PHPUNIT, Tools::RECTOR, Tools::STYLELINT]] + $expected_defaults, ]; yield 'tools - discovery - all tools' => [ [], - [Tools::id() => [Tools::BEHAT, Tools::ESLINT, Tools::PHPCS, Tools::PHPMD, Tools::PHPSTAN, Tools::PHPUNIT, Tools::RECTOR, Tools::STYLELINT]] + $expected_installed, + [Tools::id() => [Tools::BEHAT, Tools::ESLINT, Tools::JEST, Tools::PHPCS, Tools::PHPMD, Tools::PHPSTAN, Tools::PHPUNIT, Tools::RECTOR, Tools::STYLELINT]] + $expected_installed, function (AbstractHandlerDiscoveryTestCase $test, Config $config): void { $test->stubVortexProject($config); $dependencies = [ @@ -34,7 +34,7 @@ function (AbstractHandlerDiscoveryTestCase $test, Config $config): void { 'behat/behat' => '*', ]; $test->stubComposerJsonDependencies($dependencies, TRUE); - file_put_contents(static::$sut . '/package.json', json_encode(['devDependencies' => ['eslint' => '*', 'stylelint' => '*']], JSON_PRETTY_PRINT)); + file_put_contents(static::$sut . '/package.json', json_encode(['devDependencies' => ['eslint' => '*', 'jest' => '*', 'stylelint' => '*']], JSON_PRETTY_PRINT)); }, ]; yield 'tools - discovery - none' => [ @@ -180,6 +180,22 @@ function (AbstractHandlerDiscoveryTestCase $test, Config $config): void { File::dump(static::$sut . '/behat.yml'); }, ]; + yield 'tools - discovery - jest' => [ + [], + [Tools::id() => [Tools::JEST]] + $expected_installed, + function (AbstractHandlerDiscoveryTestCase $test, Config $config): void { + $test->stubVortexProject($config); + file_put_contents(static::$sut . '/package.json', json_encode(['devDependencies' => ['jest' => '*']], JSON_PRETTY_PRINT)); + }, + ]; + yield 'tools - discovery - jest, alt' => [ + [], + [Tools::id() => [Tools::JEST]] + $expected_installed, + function (AbstractHandlerDiscoveryTestCase $test, Config $config): void { + $test->stubVortexProject($config); + File::dump(static::$sut . '/jest.config.js'); + }, + ]; yield 'tools - discovery - eslint' => [ [], [Tools::id() => [Tools::ESLINT]] + $expected_installed, diff --git a/AGENTS.md b/AGENTS.md index 29c26d3f4..80d3ac594 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -69,6 +69,9 @@ ahoy test-kernel # Run PHPUnit Kernel tests ahoy test-functional # Run PHPUnit Functional tests ahoy test -- --filter=TestClassName # Run specific PHPUnit test class +# Jest testing +ahoy test-js # Run Jest JavaScript unit tests + # Behat testing ahoy test-bdd # Run Behat tests ahoy test-bdd -- --tags=@tagname # Run Behat tests with specific tag diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 000000000..b7a265ec8 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,26 @@ +const fs = require('fs'); +const path = require('path'); + +// Discover js/ directories in custom modules, resolving symlinks to real +// paths. Jest resolves symlinks internally, so roots must use real paths +// for test files to be matched. +const dirs = ['web/modules/custom']; +const roots = []; + +dirs.forEach((dir) => { + if (fs.existsSync(dir)) { + fs.readdirSync(dir).forEach((name) => { + const jsDir = path.resolve(dir, name, 'js'); + if (fs.existsSync(jsDir)) { + roots.push(jsDir); + } + }); + } +}); + +module.exports = { + testEnvironment: 'jsdom', + roots, + testMatch: ['**/*.test.js'], + testPathIgnorePatterns: ['/node_modules/', '/vendor/'], +}; diff --git a/package.json b/package.json index c2363d2a5..0fbe69c09 100644 --- a/package.json +++ b/package.json @@ -13,10 +13,13 @@ "lint": "yarn run lint-js && yarn run lint-css", "lint-fix-js": "eslint web/modules/custom --ext .js --no-error-on-unmatched-pattern --fix", "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", - "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css" + "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", + "test": "jest" }, "devDependencies": { "@homer0/prettier-plugin-jsdoc": "^11.0.1", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", "eslint": "^8.57.1", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-prettier": "^10.1.8", diff --git a/web/modules/custom/ys_demo/js/ys_demo.js b/web/modules/custom/ys_demo/js/ys_demo.js index 5f917a4b9..3b027b983 100644 --- a/web/modules/custom/ys_demo/js/ys_demo.js +++ b/web/modules/custom/ys_demo/js/ys_demo.js @@ -4,6 +4,8 @@ ((Drupal) => { Drupal.behaviors.ysDemo = { + storageKey: 'ys_counter_value', + attach(context) { this.initCounterBlock(context); }, @@ -17,7 +19,7 @@ initCounterBlock(context) { const counterBlocks = context.querySelectorAll('[data-ys-demo-counter]'); - counterBlocks.forEach(function processBlock(block) { + counterBlocks.forEach((block) => { // Skip if already processed. if (block.classList.contains('ys-demo-counter-processed')) { return; @@ -29,39 +31,24 @@ const buttons = block.querySelectorAll('[data-counter-action]'); // Load saved value from localStorage. - const storageKey = 'ys_counter_value'; - let currentValue = parseInt(localStorage.getItem(storageKey), 10) || 0; + let currentValue = this.getCounterValue(); valueElement.textContent = currentValue; // Add event listeners to buttons. - buttons.forEach(function processButton(button) { - button.addEventListener('click', function handleClick() { - const action = this.getAttribute('data-counter-action'); - - switch (action) { - case 'increment': - currentValue += 1; - break; - case 'decrement': - currentValue -= 1; - break; - case 'reset': - currentValue = 0; - break; - default: - // No action for unknown action types. - break; - } + buttons.forEach((button) => { + button.addEventListener('click', () => { + const action = button.getAttribute('data-counter-action'); + currentValue = this.applyAction(currentValue, action); - // Update display + // Update display. valueElement.textContent = currentValue; // Save to localStorage. - localStorage.setItem(storageKey, currentValue.toString()); + localStorage.setItem(this.storageKey, currentValue.toString()); // Add visual feedback. valueElement.classList.add('updated'); - Drupal.behaviors.ysDemo.removeUpdatedClassAfterDelay(valueElement); + this.removeUpdatedClassAfterDelay(valueElement); // Log action for debugging. // eslint-disable-next-line no-console @@ -71,6 +58,26 @@ }); }, + /** + * Apply a counter action and return the new value. + * + * @param {number} value The current counter value. + * @param {string} action The action to apply. + * @return {number} The new counter value. + */ + applyAction(value, action) { + switch (action) { + case 'increment': + return value + 1; + case 'decrement': + return value - 1; + case 'reset': + return 0; + default: + return value; + } + }, + /** * Remove updated class after a delay for visual feedback. * @@ -88,8 +95,7 @@ * @return {number} The current counter value, or 0 if not set. */ getCounterValue() { - const storageKey = 'ys_counter_value'; - return parseInt(localStorage.getItem(storageKey), 10) || 0; + return parseInt(localStorage.getItem(this.storageKey), 10) || 0; }, }; })(Drupal); diff --git a/web/modules/custom/ys_demo/js/ys_demo.test.js b/web/modules/custom/ys_demo/js/ys_demo.test.js new file mode 100644 index 000000000..3b51d2539 --- /dev/null +++ b/web/modules/custom/ys_demo/js/ys_demo.test.js @@ -0,0 +1,270 @@ +const fs = require('fs'); +const path = require('path'); + +describe('Drupal.behaviors.ysDemo', () => { + beforeEach(() => { + localStorage.clear(); + global.Drupal = { behaviors: {} }; + + const filePath = path.resolve(__dirname, 'ys_demo.js'); + const code = fs.readFileSync(filePath, 'utf8'); + eval(code); + }); + + afterEach(() => { + delete global.Drupal; + }); + + function createCounterBlockHtml() { + return ` +
+ 0 + + + +
+ `; + } + + describe('storageKey', () => { + it('should have the expected storage key', () => { + expect(Drupal.behaviors.ysDemo.storageKey).toBe('ys_counter_value'); + }); + }); + + describe('getCounterValue', () => { + it('should return 0 when localStorage is empty', () => { + expect(Drupal.behaviors.ysDemo.getCounterValue()).toBe(0); + }); + + it('should return the stored value from localStorage', () => { + localStorage.setItem('ys_counter_value', '42'); + expect(Drupal.behaviors.ysDemo.getCounterValue()).toBe(42); + }); + + it('should return 0 for non-numeric localStorage values', () => { + localStorage.setItem('ys_counter_value', 'invalid'); + expect(Drupal.behaviors.ysDemo.getCounterValue()).toBe(0); + }); + + it('should return negative values correctly', () => { + localStorage.setItem('ys_counter_value', '-5'); + expect(Drupal.behaviors.ysDemo.getCounterValue()).toBe(-5); + }); + }); + + describe('applyAction', () => { + it('should increment the value', () => { + expect(Drupal.behaviors.ysDemo.applyAction(0, 'increment')).toBe(1); + expect(Drupal.behaviors.ysDemo.applyAction(10, 'increment')).toBe(11); + }); + + it('should decrement the value', () => { + expect(Drupal.behaviors.ysDemo.applyAction(0, 'decrement')).toBe(-1); + expect(Drupal.behaviors.ysDemo.applyAction(5, 'decrement')).toBe(4); + }); + + it('should reset the value to zero', () => { + expect(Drupal.behaviors.ysDemo.applyAction(42, 'reset')).toBe(0); + expect(Drupal.behaviors.ysDemo.applyAction(-5, 'reset')).toBe(0); + }); + + it('should return the same value for unknown actions', () => { + expect(Drupal.behaviors.ysDemo.applyAction(7, 'unknown')).toBe(7); + }); + }); + + describe('removeUpdatedClassAfterDelay', () => { + beforeEach(() => { + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + it('should remove the updated class after 300ms', () => { + document.body.innerHTML = ''; + const element = document.querySelector('span'); + + Drupal.behaviors.ysDemo.removeUpdatedClassAfterDelay(element); + + expect(element.classList.contains('updated')).toBe(true); + jest.advanceTimersByTime(300); + expect(element.classList.contains('updated')).toBe(false); + }); + + it('should not remove the class before 300ms', () => { + document.body.innerHTML = ''; + const element = document.querySelector('span'); + + Drupal.behaviors.ysDemo.removeUpdatedClassAfterDelay(element); + + jest.advanceTimersByTime(299); + expect(element.classList.contains('updated')).toBe(true); + }); + }); + + describe('initCounterBlock', () => { + it('should initialize the counter display with 0', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('0'); + }); + + it('should initialize with saved localStorage value', () => { + localStorage.setItem('ys_counter_value', '15'); + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('15'); + }); + + it('should mark the block as processed', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const block = document.querySelector('[data-ys-demo-counter]'); + expect(block.classList.contains('ys-demo-counter-processed')).toBe(true); + }); + + it('should not re-process already processed blocks', () => { + document.body.innerHTML = createCounterBlockHtml(); + const block = document.querySelector('[data-ys-demo-counter]'); + block.classList.add('ys-demo-counter-processed'); + + const value = document.querySelector('[data-counter-value]'); + value.textContent = 'original'; + + Drupal.behaviors.ysDemo.initCounterBlock(document); + + expect(value.textContent).toBe('original'); + }); + + it('should increment counter on button click', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('1'); + }); + + it('should decrement counter on button click', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const decrementBtn = document.querySelector( + '[data-counter-action="decrement"]', + ); + decrementBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('-1'); + }); + + it('should reset counter on button click', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + incrementBtn.click(); + incrementBtn.click(); + + const resetBtn = document.querySelector('[data-counter-action="reset"]'); + resetBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('0'); + }); + + it('should save counter value to localStorage on click', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + incrementBtn.click(); + + expect(localStorage.getItem('ys_counter_value')).toBe('2'); + }); + + it('should add updated class on click for visual feedback', () => { + jest.useFakeTimers(); + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.classList.contains('updated')).toBe(true); + + jest.advanceTimersByTime(300); + expect(value.classList.contains('updated')).toBe(false); + jest.useRealTimers(); + }); + + it('should handle multiple counter blocks', () => { + document.body.innerHTML = ` +
+ 0 + +
+
+ 0 + +
+ `; + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const blocks = document.querySelectorAll('[data-ys-demo-counter]'); + expect(blocks[0].classList.contains('ys-demo-counter-processed')).toBe( + true, + ); + expect(blocks[1].classList.contains('ys-demo-counter-processed')).toBe( + true, + ); + }); + }); + + describe('attach', () => { + it('should call initCounterBlock with the context', () => { + document.body.innerHTML = createCounterBlockHtml(); + const spy = jest.spyOn(Drupal.behaviors.ysDemo, 'initCounterBlock'); + + Drupal.behaviors.ysDemo.attach(document); + + expect(spy).toHaveBeenCalledWith(document); + spy.mockRestore(); + }); + + it('should fully initialize when called as a behavior', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.attach(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('1'); + expect(localStorage.getItem('ys_counter_value')).toBe('1'); + }); + }); +}); diff --git a/yarn.lock b/yarn.lock index f3ed4f408..6fdcef7b7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,7 +2,7 @@ # yarn lockfile v1 -"@babel/code-frame@^7.0.0": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.28.6", "@babel/code-frame@^7.29.0": version "7.29.0" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.29.0.tgz#7cd7a59f15b3cc0dcd803038f7792712a7d0b15c" integrity sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw== @@ -11,11 +11,265 @@ js-tokens "^4.0.0" picocolors "^1.1.1" +"@babel/compat-data@^7.28.6": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.29.0.tgz#00d03e8c0ac24dd9be942c5370990cbe1f17d88d" + integrity sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg== + +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.29.0.tgz#5286ad785df7f79d656e88ce86e650d16ca5f322" + integrity sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA== + dependencies: + "@babel/code-frame" "^7.29.0" + "@babel/generator" "^7.29.0" + "@babel/helper-compilation-targets" "^7.28.6" + "@babel/helper-module-transforms" "^7.28.6" + "@babel/helpers" "^7.28.6" + "@babel/parser" "^7.29.0" + "@babel/template" "^7.28.6" + "@babel/traverse" "^7.29.0" + "@babel/types" "^7.29.0" + "@jridgewell/remapping" "^2.3.5" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.29.0", "@babel/generator@^7.7.2": + version "7.29.1" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.1.tgz#d09876290111abbb00ef962a7b83a5307fba0d50" + integrity sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw== + dependencies: + "@babel/parser" "^7.29.0" + "@babel/types" "^7.29.0" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + +"@babel/helper-compilation-targets@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz#32c4a3f41f12ed1532179b108a4d746e105c2b25" + integrity sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA== + dependencies: + "@babel/compat-data" "^7.28.6" + "@babel/helper-validator-option" "^7.27.1" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-globals@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" + integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== + +"@babel/helper-module-imports@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz#60632cbd6ffb70b22823187201116762a03e2d5c" + integrity sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw== + dependencies: + "@babel/traverse" "^7.28.6" + "@babel/types" "^7.28.6" + +"@babel/helper-module-transforms@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz#9312d9d9e56edc35aeb6e95c25d4106b50b9eb1e" + integrity sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA== + dependencies: + "@babel/helper-module-imports" "^7.28.6" + "@babel/helper-validator-identifier" "^7.28.5" + "@babel/traverse" "^7.28.6" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.28.6", "@babel/helper-plugin-utils@^7.8.0": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz#6f13ea251b68c8532e985fd532f28741a8af9ac8" + integrity sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug== + +"@babel/helper-string-parser@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" + integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== + "@babel/helper-validator-identifier@^7.28.5": version "7.28.5" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4" integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q== +"@babel/helper-validator-option@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" + integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== + +"@babel/helpers@^7.28.6": + version "7.29.2" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.29.2.tgz#9cfbccb02b8e229892c0b07038052cc1a8709c49" + integrity sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw== + dependencies: + "@babel/template" "^7.28.6" + "@babel/types" "^7.29.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.28.6", "@babel/parser@^7.29.0": + version "7.29.2" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.2.tgz#58bd50b9a7951d134988a1ae177a35ef9a703ba1" + integrity sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA== + dependencies: + "@babel/types" "^7.29.0" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-import-attributes@^7.24.7": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz#b71d5914665f60124e133696f17cd7669062c503" + integrity sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-syntax-import-meta@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz#f8ca28bbd84883b5fea0e447c635b81ba73997ee" + integrity sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz#c7b2ddf1d0a811145b1de800d1abd146af92e3a2" + integrity sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/template@^7.28.6", "@babel/template@^7.3.3": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.28.6.tgz#0e7e56ecedb78aeef66ce7972b082fce76a23e57" + integrity sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ== + dependencies: + "@babel/code-frame" "^7.28.6" + "@babel/parser" "^7.28.6" + "@babel/types" "^7.28.6" + +"@babel/traverse@^7.28.6", "@babel/traverse@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.0.tgz#f323d05001440253eead3c9c858adbe00b90310a" + integrity sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA== + dependencies: + "@babel/code-frame" "^7.29.0" + "@babel/generator" "^7.29.0" + "@babel/helper-globals" "^7.28.0" + "@babel/parser" "^7.29.0" + "@babel/template" "^7.28.6" + "@babel/types" "^7.29.0" + debug "^4.3.1" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.28.2", "@babel/types@^7.28.6", "@babel/types@^7.29.0", "@babel/types@^7.3.3": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.0.tgz#9f5b1e838c446e72cf3cd4b918152b8c605e37c7" + integrity sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.28.5" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + "@cacheable/memory@^2.0.7": version "2.0.7" resolved "https://registry.yarnpkg.com/@cacheable/memory/-/memory-2.0.7.tgz#1e066dc543b7c6797d0d230ce23d90898aca14c7" @@ -139,6 +393,248 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== + dependencies: + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" + integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== + dependencies: + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== + dependencies: + jest-get-type "^29.6.3" + +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== + dependencies: + expect "^29.7.0" + jest-snapshot "^29.7.0" + +"@jest/fake-timers@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" + integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== + dependencies: + "@jest/types" "^29.6.3" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" + +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^6.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== + dependencies: + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== + dependencies: + "@jest/test-result" "^29.7.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + slash "^3.0.0" + +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== + dependencies: + "@jest/schemas" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5": + version "0.3.13" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz#6342a19f44347518c93e43b1ac69deb3c4656a1f" + integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/remapping@^2.3.5": + version "2.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/remapping/-/remapping-2.3.5.tgz#375c476d1972947851ba1e15ae8f123047445aa1" + integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" + integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.28": + version "0.3.31" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0" + integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@keyv/bigmap@^1.3.0": version "1.3.1" resolved "https://registry.yarnpkg.com/@keyv/bigmap/-/bigmap-1.3.1.tgz#fc82fa83947e7ff68c6798d08907db842771ef2c" @@ -183,21 +679,142 @@ resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== +"@sinclair/typebox@^0.27.8": + version "0.27.10" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.10.tgz#beefe675f1853f73676aecc915b2bd2ac98c4fc6" + integrity sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA== + "@sindresorhus/base62@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@sindresorhus/base62/-/base62-1.0.0.tgz#c47c42410e5212e4fa4657670e118ddfba39acd6" integrity sha512-TeheYy0ILzBEI/CO55CP6zJCSdSWeRtGnHy8U8dWSUH4I68iqTsy7HkMktR4xakThc9jotkPQUXT4ITdbV7cHA== +"@sinonjs/commons@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" + integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^10.0.2": + version "10.3.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== + dependencies: + "@sinonjs/commons" "^3.0.0" + +"@tootallnate/once@2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" + integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== + +"@types/babel__core@^7.1.14": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.27.0.tgz#b5819294c51179957afaec341442f9341e4108a9" + integrity sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.28.0.tgz#07d713d6cce0d265c9849db0cbe62d3f61f36f74" + integrity sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q== + dependencies: + "@babel/types" "^7.28.2" + "@types/estree@^1.0.8": version "1.0.8" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== +"@types/graceful-fs@^4.1.3": + version "4.1.9" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jsdom@^20.0.0": + version "20.0.1" + resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-20.0.1.tgz#07c14bc19bd2f918c1929541cdaacae894744808" + integrity sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ== + dependencies: + "@types/node" "*" + "@types/tough-cookie" "*" + parse5 "^7.0.0" + "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== +"@types/node@*": + version "25.5.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-25.5.0.tgz#5c99f37c443d9ccc4985866913f1ed364217da31" + integrity sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw== + dependencies: + undici-types "~7.18.0" + +"@types/stack-utils@^2.0.0": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== + +"@types/tough-cookie@*": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz#cb6e2a691b70cb177c6e3ae9c1d2e8b2ea8cd304" + integrity sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA== + +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^17.0.8": + version "17.0.35" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.35.tgz#07013e46aa4d7d7d50a49e15604c1c5340d4eb24" + integrity sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg== + dependencies: + "@types/yargs-parser" "*" + "@typescript-eslint/types@^8.46.4": version "8.56.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.56.0.tgz#a2444011b9a98ca13d70411d2cbfed5443b3526a" @@ -208,16 +825,43 @@ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== +abab@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" + integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== + +acorn-globals@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-7.0.1.tgz#0dbf05c44fa7c94332914c02066d5beff62c40c3" + integrity sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q== + dependencies: + acorn "^8.1.0" + acorn-walk "^8.0.2" + acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.15.0, acorn@^8.9.0: +acorn-walk@^8.0.2: + version "8.3.5" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.5.tgz#8a6b8ca8fc5b34685af15dabb44118663c296496" + integrity sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw== + dependencies: + acorn "^8.11.0" + +acorn@^8.1.0, acorn@^8.11.0, acorn@^8.15.0, acorn@^8.8.1, acorn@^8.9.0: version "8.16.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.16.0.tgz#4ce79c89be40afe7afe8f3adb902a1f1ce9ac08a" integrity sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw== +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -238,6 +882,13 @@ ajv@^8.0.1: json-schema-traverse "^1.0.0" require-from-string "^2.0.2" +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" @@ -250,11 +901,31 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +anymatch@^3.0.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + are-docs-informative@^0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/are-docs-informative/-/are-docs-informative-0.0.2.tgz#387f0e93f5d45280373d387a59d34c96db321963" integrity sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig== +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + argparse@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" @@ -343,6 +1014,11 @@ async-function@^1.0.0: resolved "https://registry.yarnpkg.com/async-function/-/async-function-1.0.0.tgz#509c9fca60eaf85034c6829838188e4e4c8ffb2b" integrity sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA== +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + available-typed-arrays@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" @@ -350,6 +1026,69 @@ available-typed-arrays@^1.0.7: dependencies: possible-typed-array-names "^1.0.0" +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== + dependencies: + "@jest/transform" "^29.7.0" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.6.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-preset-current-node-syntax@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz#20730d6cdc7dda5d89401cab10ac6a32067acde6" + integrity sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-import-attributes" "^7.24.7" + "@babel/plugin-syntax-import-meta" "^7.10.4" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== + dependencies: + babel-plugin-jest-hoist "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -360,6 +1099,11 @@ balanced-match@^2.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-2.0.0.tgz#dc70f920d78db8b858535795867bf48f820633d9" integrity sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA== +baseline-browser-mapping@^2.9.0: + version "2.10.10" + resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.10.10.tgz#e74bd066724c1d8d7d8ea75fc3be25389a7a5c56" + integrity sha512-sUoJ3IMxx4AyRqO4MLeHlnGDkyXRoUG0/AI9fjK+vS72ekpV0yWVY7O0BVjmBcRtkNcsAO2QDZ4tdKKGoI6YaQ== + brace-expansion@^1.1.7: version "1.1.12" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843" @@ -375,6 +1119,29 @@ braces@^3.0.3: dependencies: fill-range "^7.1.1" +browserslist@^4.24.0: + version "4.28.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.1.tgz#7f534594628c53c63101079e27e40de490456a95" + integrity sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA== + dependencies: + baseline-browser-mapping "^2.9.0" + caniuse-lite "^1.0.30001759" + electron-to-chromium "^1.5.263" + node-releases "^2.0.27" + update-browserslist-db "^1.2.0" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + cacheable@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/cacheable/-/cacheable-2.3.2.tgz#89800b4864c3ab8b23dae6dca8b6232cbf49b299" @@ -417,6 +1184,21 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001759: + version "1.0.30001781" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001781.tgz#344b47c03eb8168b79c3c158b872bcfbdd02a400" + integrity sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw== + chalk@^4.0.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -425,6 +1207,40 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +ci-info@^3.2.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + +cjs-module-lexer@^1.0.0: + version "1.4.3" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz#0f79731eb8cfe1ec72acd4066efac9d61991b00d" + integrity sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q== + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz#cc1f01eb8d02298cbc9a437c74c70ab4e5210b80" + integrity sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw== + color-convert@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -442,6 +1258,13 @@ colord@^2.9.3: resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43" integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw== +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + comment-parser@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.4.1.tgz#bdafead37961ac079be11eb7ec65c4d021eaf9cc" @@ -462,6 +1285,11 @@ confusing-browser-globals@^1.0.10: resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81" integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA== +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + cosmiconfig@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-9.0.0.tgz#34c3fc58287b915f3ae905ab6dc3de258b55ad9d" @@ -472,7 +1300,20 @@ cosmiconfig@^9.0.0: js-yaml "^4.1.0" parse-json "^5.2.0" -cross-spawn@^7.0.2: +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" + +cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== @@ -499,6 +1340,32 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== +cssom@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.5.0.tgz#d254fa92cd8b6fbd83811b9fbaed34663cc17c36" + integrity sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw== + +cssom@~0.3.6: + version "0.3.8" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== + dependencies: + cssom "~0.3.6" + +data-urls@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-3.0.2.tgz#9cf24a477ae22bcef5cd5f6f0bfbc1d2d3be9143" + integrity sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ== + dependencies: + abab "^2.0.6" + whatwg-mimetype "^3.0.0" + whatwg-url "^11.0.0" + data-view-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz#211a03ba95ecaf7798a8c7198d79536211f88570" @@ -526,6 +1393,13 @@ data-view-byte-offset@^1.0.1: es-errors "^1.3.0" is-data-view "^1.0.1" +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.4.3: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -533,18 +1407,26 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.3.1, debug@^4.3.2, debug@^4.4.3: - version "4.4.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" - integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== - dependencies: - ms "^2.1.3" +decimal.js@^10.4.2: + version "10.6.0" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.6.0.tgz#e649a43e3ab953a72192ff5983865e509f37ed9a" + integrity sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg== + +dedent@^1.0.0: + version "1.7.2" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.7.2.tgz#34e2264ab538301e27cf7b07bf2369c19baa8dd9" + integrity sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA== deep-is@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== +deepmerge@^4.2.2: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + define-data-property@^1.0.1, define-data-property@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" @@ -563,11 +1445,26 @@ define-properties@^1.2.1: has-property-descriptors "^1.0.0" object-keys "^1.1.1" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + diff-sequences@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -589,6 +1486,13 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +domexception@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-4.0.0.tgz#4ad1be56ccadc86fc76d033353999a8037d03673" + integrity sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw== + dependencies: + webidl-conversions "^7.0.0" + dunder-proto@^1.0.0, dunder-proto@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" @@ -598,11 +1502,26 @@ dunder-proto@^1.0.0, dunder-proto@^1.0.1: es-errors "^1.3.0" gopd "^1.2.0" +electron-to-chromium@^1.5.263: + version "1.5.322" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.322.tgz#9c24e49f7098ca19bc87c0e9c7e0ad6ffe4fddca" + integrity sha512-vFU34OcrvMcH66T+dYC3G4nURmgfDVewMIu6Q2urXpumAPSMmzvcn04KVVV8Opikq8Vs5nUbO/8laNhNRqSzYw== + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +entities@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-6.0.1.tgz#c28c34a43379ca7f61d074130b2f5f7020a30694" + integrity sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g== + env-paths@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" @@ -718,11 +1637,32 @@ es-to-primitive@^1.3.0: is-date-object "^1.0.5" is-symbol "^1.0.4" +escalade@^3.1.1, escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escodegen@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.1.0.tgz#ba93bbb7a43986d29d6041f99f5262da773e2e17" + integrity sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionalDependencies: + source-map "~0.6.1" + eslint-compat-utils@^0.6.0: version "0.6.5" resolved "https://registry.yarnpkg.com/eslint-compat-utils/-/eslint-compat-utils-0.6.5.tgz#6b06350a1c947c4514cfa64a170a6bfdbadc7ec2" @@ -911,6 +1851,11 @@ espree@^9.6.0, espree@^9.6.1: acorn-jsx "^5.3.2" eslint-visitor-keys "^3.4.1" +esprima@^4.0.0, esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + esquery@^1.4.2, esquery@^1.6.0, esquery@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.7.0.tgz#08d048f261f0ddedb5bae95f46809463d9c9496d" @@ -935,6 +1880,37 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expect@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== + dependencies: + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -956,7 +1932,7 @@ fast-glob@^3.2.9, fast-glob@^3.3.3: merge2 "^1.3.0" micromatch "^4.0.8" -fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -983,6 +1959,13 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + file-entry-cache@^11.1.1: version "11.1.2" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-11.1.2.tgz#5b2014aac2259b5591ae6fd7f6d1ed2153545abe" @@ -1004,6 +1987,14 @@ fill-range@^7.1.1: dependencies: to-regex-range "^5.0.1" +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + find-up@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" @@ -1042,11 +2033,27 @@ for-each@^0.3.3, for-each@^0.3.5: dependencies: is-callable "^1.2.7" +form-data@^4.0.0: + version "4.0.5" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.5.tgz#b49e48858045ff4cbf6b03e1805cebcad3679053" + integrity sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + hasown "^2.0.2" + mime-types "^2.1.12" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +fsevents@^2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + function-bind@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" @@ -1074,6 +2081,16 @@ generator-function@^2.0.0: resolved "https://registry.yarnpkg.com/generator-function/-/generator-function-2.0.1.tgz#0e75dd410d1243687a0ba2e951b94eedb8f737a2" integrity sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g== +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.2.7, get-intrinsic@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" @@ -1090,6 +2107,11 @@ get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@ hasown "^2.0.2" math-intrinsics "^1.1.0" +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + get-proto@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" @@ -1098,6 +2120,11 @@ get-proto@^1.0.1: dunder-proto "^1.0.1" es-object-atoms "^1.0.0" +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + get-symbol-description@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz#7bdd54e0befe8ffc9f3b4e203220d9f1e881b6ee" @@ -1121,7 +2148,7 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob@^7.1.3: +glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -1186,6 +2213,11 @@ gopd@^1.0.1, gopd@^1.2.0: resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== +graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + graphemer@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" @@ -1246,16 +2278,57 @@ hookified@^1.14.0, hookified@^1.15.0: resolved "https://registry.yarnpkg.com/hookified/-/hookified-1.15.1.tgz#b1fafeaa5489cdc29cb85546a8f837ed4ffbbcb6" integrity sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg== +html-encoding-sniffer@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz#2cb1a8cf0db52414776e5b2a7a04d5dd98158de9" + integrity sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA== + dependencies: + whatwg-encoding "^2.0.0" + html-entities@^2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.6.0.tgz#7c64f1ea3b36818ccae3d3fb48b6974208e984f8" integrity sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ== +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + html-tags@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.3.1.tgz#a04026a18c882e4bba8a01a3d39cfe465d40b5ce" integrity sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ== +http-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" + integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w== + dependencies: + "@tootallnate/once" "2" + agent-base "6" + debug "4" + +https-proxy-agent@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + ignore@^5.2.0: version "5.3.2" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" @@ -1274,6 +2347,14 @@ import-fresh@^3.2.1, import-fresh@^3.3.0: parent-module "^1.0.0" resolve-from "^4.0.0" +import-local@^3.0.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" + integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -1392,6 +2473,11 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + is-generator-function@^1.0.10: version "1.1.2" resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.1.2.tgz#ae3b61e3d5ea4e4839b90bad22b02335051a17d5" @@ -1443,6 +2529,11 @@ is-plain-object@^5.0.0: resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + is-regex@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22" @@ -1465,6 +2556,11 @@ is-shared-array-buffer@^1.0.4: dependencies: call-bound "^1.0.3" +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + is-string@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.1.1.tgz#92ea3f3d5c5b6e039ca8677e5ac8d07ea773cbb9" @@ -1519,11 +2615,444 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-instrument@^5.0.4: + version "5.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-instrument@^6.0.0: + version "6.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" + integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== + dependencies: + "@babel/core" "^7.23.9" + "@babel/parser" "^7.23.9" + "@istanbuljs/schema" "^0.1.3" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.2.0.tgz#cb4535162b5784aa623cee21a7252cf2c807ac93" + integrity sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== + dependencies: + execa "^5.0.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^1.0.0" + is-generator-fn "^2.0.0" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + pretty-format "^29.7.0" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== + dependencies: + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + chalk "^4.0.0" + create-jest "^29.7.0" + exit "^0.1.2" + import-local "^3.0.2" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + yargs "^17.3.1" + +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.0" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== + dependencies: + detect-newline "^3.0.0" + +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + +jest-environment-jsdom@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz#d206fa3551933c3fd519e5dfdb58a0f5139a837f" + integrity sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/jsdom" "^20.0.0" + "@types/node" "*" + jest-mock "^29.7.0" + jest-util "^29.7.0" + jsdom "^20.0.0" + +jest-environment-node@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" + integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== + +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== + dependencies: + "@jest/types" "^29.6.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== + dependencies: + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== + dependencies: + chalk "^4.0.0" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" + integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-util "^29.7.0" + +jest-pnp-resolver@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== + +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== + dependencies: + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" + +jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-pnp-resolver "^1.2.2" + jest-util "^29.7.0" + jest-validate "^29.7.0" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== + dependencies: + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.7.0" + graceful-fs "^4.2.9" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + natural-compare "^1.4.0" + pretty-format "^29.7.0" + semver "^7.5.3" + +jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" + integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== + dependencies: + "@jest/types" "^29.6.3" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.6.3" + leven "^3.1.0" + pretty-format "^29.7.0" + +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== + dependencies: + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.7.0" + string-length "^4.0.1" + +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== + dependencies: + "@types/node" "*" + jest-util "^29.7.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== + dependencies: + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" + import-local "^3.0.2" + jest-cli "^29.7.0" + js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== +js-yaml@^3.13.1: + version "3.14.2" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.2.tgz#77485ce1dd7f33c061fd1b16ecea23b55fcb04b0" + integrity sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + js-yaml@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b" @@ -1536,6 +3065,43 @@ jsdoc-type-pratt-parser@~7.0.0: resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-7.0.0.tgz#b0381514e79aa6326185078059ca5915bb8ede3b" integrity sha512-c7YbokssPOSHmqTbSAmTtnVgAVa/7lumWNYqomgd5KOMyPrRve2anx6lonfOsXEQacqF9FKVUj7bLg4vRSvdYA== +jsdom@^20.0.0: + version "20.0.3" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-20.0.3.tgz#886a41ba1d4726f67a8858028c99489fed6ad4db" + integrity sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ== + dependencies: + abab "^2.0.6" + acorn "^8.8.1" + acorn-globals "^7.0.0" + cssom "^0.5.0" + cssstyle "^2.3.0" + data-urls "^3.0.2" + decimal.js "^10.4.2" + domexception "^4.0.0" + escodegen "^2.0.0" + form-data "^4.0.0" + html-encoding-sniffer "^3.0.0" + http-proxy-agent "^5.0.0" + https-proxy-agent "^5.0.1" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.2" + parse5 "^7.1.1" + saxes "^6.0.0" + symbol-tree "^3.2.4" + tough-cookie "^4.1.2" + w3c-xmlserializer "^4.0.0" + webidl-conversions "^7.0.0" + whatwg-encoding "^2.0.0" + whatwg-mimetype "^3.0.0" + whatwg-url "^11.0.0" + ws "^8.11.0" + xml-name-validator "^4.0.0" + +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + json-buffer@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" @@ -1568,6 +3134,11 @@ json5@^1.0.2: dependencies: minimist "^1.2.0" +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + keyv@^4.5.3: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" @@ -1587,11 +3158,21 @@ kind-of@^6.0.2: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + known-css-properties@^0.37.0: version "0.37.0" resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.37.0.tgz#10ebe49b9dbb6638860ff8a002fb65a053f4aec5" integrity sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ== +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -1605,6 +3186,13 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + locate-path@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" @@ -1622,6 +3210,27 @@ lodash.truncate@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + math-intrinsics@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" @@ -1642,12 +3251,17 @@ meow@^13.2.0: resolved "https://registry.yarnpkg.com/meow/-/meow-13.2.0.tgz#6b7d63f913f984063b3cc261b6e8800c4cd3474f" integrity sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA== +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -micromatch@^4.0.8: +micromatch@^4.0.4, micromatch@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== @@ -1655,6 +3269,30 @@ micromatch@^4.0.8: braces "^3.0.3" picomatch "^2.3.1" +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimatch@^3.0.4: + version "3.1.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.5.tgz#580c88f8d5445f2bd6aa8f3cadefa0de79fbd69e" + integrity sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w== + dependencies: + brace-expansion "^1.1.7" + minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -1682,11 +3320,33 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.27: + version "2.0.36" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.36.tgz#99fd6552aaeda9e17c4713b57a63964a2e325e9d" + integrity sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA== + normalize-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +nwsapi@^2.2.2: + version "2.2.23" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.23.tgz#59712c3a88e6de2bb0b6ccc1070397267019cf6c" + integrity sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ== + object-deep-merge@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/object-deep-merge/-/object-deep-merge-2.0.0.tgz#94d24cf713d4a7a143653500ff4488a2d494681f" @@ -1760,6 +3420,13 @@ once@^1.3.0: dependencies: wrappy "1" +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + optionator@^0.9.3: version "0.9.4" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" @@ -1781,13 +3448,27 @@ own-keys@^1.0.1: object-keys "^1.1.1" safe-push-apply "^1.0.0" -p-limit@^3.0.2: +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2, p-limit@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: yocto-queue "^0.1.0" +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + p-locate@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" @@ -1795,6 +3476,11 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -1824,6 +3510,13 @@ parse-statements@1.0.11: resolved "https://registry.yarnpkg.com/parse-statements/-/parse-statements-1.0.11.tgz#8787c5d383ae5746568571614be72b0689584344" integrity sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA== +parse5@^7.0.0, parse5@^7.1.1: + version "7.3.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.3.0.tgz#d7e224fa72399c7a175099f45fc2ad024b05ec05" + integrity sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw== + dependencies: + entities "^6.0.0" + path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" @@ -1834,7 +3527,7 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-key@^3.1.0: +path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== @@ -1854,11 +3547,28 @@ picocolors@^1.1.1: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== +picomatch@^2.0.4, picomatch@^2.2.3: + version "2.3.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.2.tgz#5a942915e26b372dc0f0e6753149a16e6b1c5601" + integrity sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA== + picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +pirates@^4.0.4: + version "4.0.7" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.7.tgz#643b4a18c4257c8a65104b73f3049ce9a0a15e22" + integrity sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + possible-typed-array-names@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz#93e3582bc0e5426586d9d07b79ee40fc841de4ae" @@ -1918,11 +3628,40 @@ prettier@^3.7.4: resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.8.1.tgz#edf48977cf991558f4fcbd8a3ba6015ba2a3a173" integrity sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg== -punycode@^2.1.0: +pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +psl@^1.1.33: + version "1.15.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.15.0.tgz#bdace31896f1d97cec6a79e8224898ce93d974c6" + integrity sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w== + dependencies: + punycode "^2.3.1" + +punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== +pure-rand@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" + integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== + qified@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/qified/-/qified-0.6.0.tgz#a9c33f51fa37d03003065638bb7dff45d7a81297" @@ -1930,6 +3669,11 @@ qified@^0.6.0: dependencies: hookified "^1.14.0" +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -1940,6 +3684,11 @@ ramda@0.32.0: resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.32.0.tgz#b2116807b59b6b177af7a2ad19b14a3653570e96" integrity sha512-GQWAHhxhxWBWA8oIBr1XahFVjQ9Fic6MK9ikijfd4TZHfE2+urfk+irVlR5VOn48uwMgM+loRRBJd6Yjsbc0zQ== +react-is@^18.0.0: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== + reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9: version "1.0.10" resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz#c629219e78a3316d8b604c765ef68996964e7bf9" @@ -1966,16 +3715,33 @@ regexp.prototype.flags@^1.5.4: gopd "^1.2.0" set-function-name "^2.0.2" +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + require-from-string@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + reserved-identifiers@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/reserved-identifiers/-/reserved-identifiers-1.2.0.tgz#d2982cd698e317dd3dced1ee1c52412dbd64fc64" integrity sha512-yE7KUfFvaBFzGPs5H3Ops1RevfUEsDc5Iz65rOwWg4lE8HJSYtle77uul3+573457oHvBKuHYDl/xqUkKpEEdw== +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" @@ -1986,7 +3752,12 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== -resolve@^1.22.4: +resolve.exports@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.3.tgz#41955e6f1b4013b7586f873749a635dea07ebe3f" + integrity sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A== + +resolve@^1.20.0, resolve@^1.22.4: version "1.22.11" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.11.tgz#aad857ce1ffb8bfa9b0b1ac29f1156383f68c262" integrity sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ== @@ -2042,12 +3813,24 @@ safe-regex-test@^1.1.0: es-errors "^1.3.0" is-regex "^1.2.1" +"safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +saxes@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-6.0.0.tgz#fe5b4a4768df4f14a201b1ba6a65c1f3d9988cc5" + integrity sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA== + dependencies: + xmlchars "^2.2.0" + semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.5.4, semver@^7.7.3: +semver@^7.5.3, semver@^7.5.4, semver@^7.7.3: version "7.7.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.4.tgz#28464e36060e991fa7a11d0279d2d3f3b57a7e8a" integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA== @@ -2135,11 +3918,21 @@ side-channel@^1.1.0: side-channel-map "^1.0.1" side-channel-weakmap "^1.0.2" +signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + signal-exit@^4.0.1: version "4.1.0" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -2159,6 +3952,19 @@ source-map-js@^1.0.1, source-map-js@^1.2.1: resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + spdx-exceptions@^2.1.0: version "2.5.0" resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66" @@ -2177,6 +3983,18 @@ spdx-license-ids@^3.0.0: resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz#abf5a08a6f5d7279559b669f47f0a43e8f3464ef" integrity sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ== +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + stop-iteration-iterator@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz#f481ff70a548f6124d0312c3aa14cbfa7aa542ad" @@ -2185,7 +4003,15 @@ stop-iteration-iterator@^1.1.0: es-errors "^1.3.0" internal-slot "^1.1.0" -string-width@^4.2.3: +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -2226,7 +4052,7 @@ string.prototype.trimstart@^1.0.8: define-properties "^1.2.1" es-object-atoms "^1.0.0" -strip-ansi@^6.0.1: +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -2238,6 +4064,16 @@ strip-bom@^3.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" @@ -2315,6 +4151,13 @@ supports-color@^7.0.0, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + supports-hyperlinks@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz#b8e485b179681dea496a1e7abdf8985bd3145461" @@ -2333,6 +4176,11 @@ svg-tags@^1.0.0: resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" integrity sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA== +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + synckit@^0.11.12: version "0.11.12" resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.12.tgz#abe74124264fbc00a48011b0d98bdc1cffb64a7b" @@ -2351,11 +4199,25 @@ table@^6.9.0: string-width "^4.2.3" strip-ansi "^6.0.1" +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -2371,6 +4233,23 @@ to-valid-identifier@^1.0.0: "@sindresorhus/base62" "^1.0.0" reserved-identifiers "^1.0.0" +tough-cookie@^4.1.2: + version "4.1.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36" + integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.2.0" + url-parse "^1.5.3" + +tr46@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9" + integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA== + dependencies: + punycode "^2.1.1" + tsconfig-paths@^3.15.0: version "3.15.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" @@ -2388,11 +4267,21 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + type-fest@^0.20.2: version "0.20.2" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + typed-array-buffer@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536" @@ -2448,6 +4337,24 @@ unbox-primitive@^1.1.0: has-symbols "^1.1.0" which-boxed-primitive "^1.1.1" +undici-types@~7.18.0: + version "7.18.2" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.18.2.tgz#29357a89e7b7ca4aef3bf0fd3fd0cd73884229e9" + integrity sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w== + +universalify@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== + +update-browserslist-db@^1.2.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz#64d76db58713136acbeb4c49114366cc6cc2e80d" + integrity sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.1" + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -2455,11 +4362,67 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +url-parse@^1.5.3: + version "1.5.10" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + util-deprecate@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== +v8-to-istanbul@^9.0.1: + version "9.3.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" + integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^2.0.0" + +w3c-xmlserializer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz#aebdc84920d806222936e3cdce408e32488a3073" + integrity sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw== + dependencies: + xml-name-validator "^4.0.0" + +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + +whatwg-encoding@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz#e7635f597fd87020858626805a2729fa7698ac53" + integrity sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg== + dependencies: + iconv-lite "0.6.3" + +whatwg-mimetype@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz#5fa1a7623867ff1af6ca3dc72ad6b8a4208beba7" + integrity sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q== + +whatwg-url@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-11.0.0.tgz#0a849eebb5faf2119b901bb76fd795c2848d4018" + integrity sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ== + dependencies: + tr46 "^3.0.0" + webidl-conversions "^7.0.0" + which-boxed-primitive@^1.1.0, which-boxed-primitive@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz#d76ec27df7fa165f18d5808374a5fe23c29b176e" @@ -2532,11 +4495,28 @@ word-wrap@^1.2.5: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + write-file-atomic@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-5.0.1.tgz#68df4717c55c6fa4281a7860b4c2ba0a6d2b11e7" @@ -2545,6 +4525,31 @@ write-file-atomic@^5.0.1: imurmurhash "^0.1.4" signal-exit "^4.0.1" +ws@^8.11.0: + version "8.20.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.20.0.tgz#4cd9532358eba60bc863aad1623dfb045a4d4af8" + integrity sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA== + +xml-name-validator@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835" + integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw== + +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + yaml-eslint-parser@^1.2.1: version "1.3.2" resolved "https://registry.yarnpkg.com/yaml-eslint-parser/-/yaml-eslint-parser-1.3.2.tgz#f62010fe8293d39930422d70e46f23b075bd13b5" @@ -2558,6 +4563,24 @@ yaml@^2.0.0: resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.2.tgz#5694f25eca0ce9c3e7a9d9e00ce0ddabbd9e35c5" integrity sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A== +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.3.1: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" From 1d73987db97d05b6e8911a87aaa39b3b5153250d Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 00:17:09 +1100 Subject: [PATCH 02/36] [#2394] Fixed missing 'jest' in expected default tools list in AbstractHandlerDiscoveryTestCase. --- .../tests/Unit/Handlers/AbstractHandlerDiscoveryTestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vortex/installer/tests/Unit/Handlers/AbstractHandlerDiscoveryTestCase.php b/.vortex/installer/tests/Unit/Handlers/AbstractHandlerDiscoveryTestCase.php index 8ffff020e..8d4cd0e4c 100644 --- a/.vortex/installer/tests/Unit/Handlers/AbstractHandlerDiscoveryTestCase.php +++ b/.vortex/installer/tests/Unit/Handlers/AbstractHandlerDiscoveryTestCase.php @@ -139,7 +139,7 @@ protected static function getExpectedDefaults(): array { VersionScheme::id() => VersionScheme::CALVER, Timezone::id() => 'UTC', Services::id() => [Services::CLAMAV, Services::REDIS, Services::SOLR], - Tools::id() => [Tools::BEHAT, Tools::ESLINT, Tools::PHPCS, Tools::PHPMD, Tools::PHPSTAN, Tools::PHPUNIT, Tools::RECTOR, Tools::STYLELINT], + Tools::id() => [Tools::BEHAT, Tools::ESLINT, Tools::JEST, Tools::PHPCS, Tools::PHPMD, Tools::PHPSTAN, Tools::PHPUNIT, Tools::RECTOR, Tools::STYLELINT], HostingProvider::id() => HostingProvider::NONE, HostingProjectName::id() => NULL, Webroot::id() => Webroot::WEB, From 536b605eab28e13e05288387f98075e160aaf412 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 08:24:38 +1100 Subject: [PATCH 03/36] Updated baseline. --- .../handler_process/_baseline/.ahoy.yml | 5 +- .../handler_process/_baseline/.eslintrc.json | 10 + .../.github/workflows/build-test-deploy.yml | 5 + .../handler_process/_baseline/AGENTS.md | 3 + .../handler_process/_baseline/jest.config.js | 26 ++ .../handler_process/_baseline/package.json | 5 +- .../web/modules/custom/sw_demo/js/sw_demo.js | 58 ++-- .../modules/custom/sw_demo/js/sw_demo.test.js | 270 ++++++++++++++++++ 8 files changed, 354 insertions(+), 28 deletions(-) create mode 100644 .vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/_baseline/web/modules/custom/sw_demo/js/sw_demo.test.js diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/.ahoy.yml b/.vortex/installer/tests/Fixtures/handler_process/_baseline/.ahoy.yml index c5bb74fc7..86af0b06e 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/.ahoy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/.ahoy.yml @@ -236,10 +236,13 @@ commands: cmd: ahoy cli vendor/bin/phpunit --testsuite=functional "$@" test-functional-javascript: - aliases: [test-js] usage: Run PHPUnit functional JavaScript tests. cmd: ahoy cli vendor/bin/phpunit --testsuite=functional-javascript "$@" + test-js: + usage: Run Jest JavaScript unit tests. + cmd: ahoy cli "yarn test" + test-bdd: usage: Run BDD tests. aliases: [test-behat] diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/.eslintrc.json b/.vortex/installer/tests/Fixtures/handler_process/_baseline/.eslintrc.json index ef68a6a93..7208a7e8f 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/.eslintrc.json +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/.eslintrc.json @@ -61,6 +61,16 @@ "operator-linebreak": ["error", "after", { "overrides": { "?": "ignore", ":": "ignore" } }], "yml/indent": ["error", 2] }, + "overrides": [ + { + "files": ["*.test.js"], + "env": { "jest": true }, + "rules": { + "no-eval": "off", + "max-nested-callbacks": ["warn", 5] + } + } + ], "settings": { "jsdoc": { "tagNamePreference": { diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/_baseline/.github/workflows/build-test-deploy.yml index ac5a691f1..0d6837a4e 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/.github/workflows/build-test-deploy.yml @@ -125,6 +125,7 @@ jobs: if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" - name: Audit Composer packages run: docker compose exec -T cli composer audit @@ -162,6 +163,10 @@ jobs: run: docker compose exec -T cli bash -c "yarn run lint" continue-on-error: ${{ vars.VORTEX_CI_NODEJS_LINT_IGNORE_FAILURE == '1' }} + - name: Test module code with Jest + run: docker compose exec -T cli bash -c "yarn test" + continue-on-error: ${{ vars.VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE == '1' }} + - name: Lint theme code with NodeJS linters if: ${{ vars.VORTEX_FRONTEND_BUILD_SKIP != '1' }} run: docker compose exec -T cli bash -c "yarn --cwd=\${WEBROOT}/themes/custom/\${DRUPAL_THEME} run lint" diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/AGENTS.md b/.vortex/installer/tests/Fixtures/handler_process/_baseline/AGENTS.md index 53b4ab0a3..b32df8396 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/AGENTS.md +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/AGENTS.md @@ -59,6 +59,9 @@ ahoy test-kernel # Run PHPUnit Kernel tests ahoy test-functional # Run PHPUnit Functional tests ahoy test -- --filter=TestClassName # Run specific PHPUnit test class +# Jest testing +ahoy test-js # Run Jest JavaScript unit tests + # Behat testing ahoy test-bdd # Run Behat tests ahoy test-bdd -- --tags=@tagname # Run Behat tests with specific tag diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js new file mode 100644 index 000000000..b7a265ec8 --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js @@ -0,0 +1,26 @@ +const fs = require('fs'); +const path = require('path'); + +// Discover js/ directories in custom modules, resolving symlinks to real +// paths. Jest resolves symlinks internally, so roots must use real paths +// for test files to be matched. +const dirs = ['web/modules/custom']; +const roots = []; + +dirs.forEach((dir) => { + if (fs.existsSync(dir)) { + fs.readdirSync(dir).forEach((name) => { + const jsDir = path.resolve(dir, name, 'js'); + if (fs.existsSync(jsDir)) { + roots.push(jsDir); + } + }); + } +}); + +module.exports = { + testEnvironment: 'jsdom', + roots, + testMatch: ['**/*.test.js'], + testPathIgnorePatterns: ['/node_modules/', '/vendor/'], +}; diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/package.json b/.vortex/installer/tests/Fixtures/handler_process/_baseline/package.json index e778d6707..62eac946c 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/package.json @@ -13,10 +13,13 @@ "lint": "yarn run lint-js && yarn run lint-css", "lint-fix-js": "eslint web/modules/custom --ext .js --no-error-on-unmatched-pattern --fix", "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", - "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css" + "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", + "test": "jest" }, "devDependencies": { "@homer0/prettier-plugin-jsdoc": "__VERSION__", + "jest": "__VERSION__", + "jest-environment-jsdom": "__VERSION__", "eslint": "__VERSION__", "eslint-config-airbnb-base": "__VERSION__", "eslint-config-prettier": "__VERSION__", diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/web/modules/custom/sw_demo/js/sw_demo.js b/.vortex/installer/tests/Fixtures/handler_process/_baseline/web/modules/custom/sw_demo/js/sw_demo.js index 3282266ce..886028723 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/web/modules/custom/sw_demo/js/sw_demo.js +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/web/modules/custom/sw_demo/js/sw_demo.js @@ -4,6 +4,8 @@ ((Drupal) => { Drupal.behaviors.ysDemo = { + storageKey: 'ys_counter_value', + attach(context) { this.initCounterBlock(context); }, @@ -17,7 +19,7 @@ initCounterBlock(context) { const counterBlocks = context.querySelectorAll('[data-sw-demo-counter]'); - counterBlocks.forEach(function processBlock(block) { + counterBlocks.forEach((block) => { // Skip if already processed. if (block.classList.contains('sw-demo-counter-processed')) { return; @@ -29,39 +31,24 @@ const buttons = block.querySelectorAll('[data-counter-action]'); // Load saved value from localStorage. - const storageKey = 'ys_counter_value'; - let currentValue = parseInt(localStorage.getItem(storageKey), 10) || 0; + let currentValue = this.getCounterValue(); valueElement.textContent = currentValue; // Add event listeners to buttons. - buttons.forEach(function processButton(button) { - button.addEventListener('click', function handleClick() { - const action = this.getAttribute('data-counter-action'); - - switch (action) { - case 'increment': - currentValue += 1; - break; - case 'decrement': - currentValue -= 1; - break; - case 'reset': - currentValue = 0; - break; - default: - // No action for unknown action types. - break; - } + buttons.forEach((button) => { + button.addEventListener('click', () => { + const action = button.getAttribute('data-counter-action'); + currentValue = this.applyAction(currentValue, action); - // Update display + // Update display. valueElement.textContent = currentValue; // Save to localStorage. - localStorage.setItem(storageKey, currentValue.toString()); + localStorage.setItem(this.storageKey, currentValue.toString()); // Add visual feedback. valueElement.classList.add('updated'); - Drupal.behaviors.ysDemo.removeUpdatedClassAfterDelay(valueElement); + this.removeUpdatedClassAfterDelay(valueElement); // Log action for debugging. // eslint-disable-next-line no-console @@ -71,6 +58,26 @@ }); }, + /** + * Apply a counter action and return the new value. + * + * @param {number} value The current counter value. + * @param {string} action The action to apply. + * @return {number} The new counter value. + */ + applyAction(value, action) { + switch (action) { + case 'increment': + return value + 1; + case 'decrement': + return value - 1; + case 'reset': + return 0; + default: + return value; + } + }, + /** * Remove updated class after a delay for visual feedback. * @@ -88,8 +95,7 @@ * @return {number} The current counter value, or 0 if not set. */ getCounterValue() { - const storageKey = 'ys_counter_value'; - return parseInt(localStorage.getItem(storageKey), 10) || 0; + return parseInt(localStorage.getItem(this.storageKey), 10) || 0; }, }; })(Drupal); diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/web/modules/custom/sw_demo/js/sw_demo.test.js b/.vortex/installer/tests/Fixtures/handler_process/_baseline/web/modules/custom/sw_demo/js/sw_demo.test.js new file mode 100644 index 000000000..244df74d2 --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/web/modules/custom/sw_demo/js/sw_demo.test.js @@ -0,0 +1,270 @@ +const fs = require('fs'); +const path = require('path'); + +describe('Drupal.behaviors.ysDemo', () => { + beforeEach(() => { + localStorage.clear(); + global.Drupal = { behaviors: {} }; + + const filePath = path.resolve(__dirname, 'sw_demo.js'); + const code = fs.readFileSync(filePath, 'utf8'); + eval(code); + }); + + afterEach(() => { + delete global.Drupal; + }); + + function createCounterBlockHtml() { + return ` +
+ 0 + + + +
+ `; + } + + describe('storageKey', () => { + it('should have the expected storage key', () => { + expect(Drupal.behaviors.ysDemo.storageKey).toBe('ys_counter_value'); + }); + }); + + describe('getCounterValue', () => { + it('should return 0 when localStorage is empty', () => { + expect(Drupal.behaviors.ysDemo.getCounterValue()).toBe(0); + }); + + it('should return the stored value from localStorage', () => { + localStorage.setItem('ys_counter_value', '42'); + expect(Drupal.behaviors.ysDemo.getCounterValue()).toBe(42); + }); + + it('should return 0 for non-numeric localStorage values', () => { + localStorage.setItem('ys_counter_value', 'invalid'); + expect(Drupal.behaviors.ysDemo.getCounterValue()).toBe(0); + }); + + it('should return negative values correctly', () => { + localStorage.setItem('ys_counter_value', '-5'); + expect(Drupal.behaviors.ysDemo.getCounterValue()).toBe(-5); + }); + }); + + describe('applyAction', () => { + it('should increment the value', () => { + expect(Drupal.behaviors.ysDemo.applyAction(0, 'increment')).toBe(1); + expect(Drupal.behaviors.ysDemo.applyAction(10, 'increment')).toBe(11); + }); + + it('should decrement the value', () => { + expect(Drupal.behaviors.ysDemo.applyAction(0, 'decrement')).toBe(-1); + expect(Drupal.behaviors.ysDemo.applyAction(5, 'decrement')).toBe(4); + }); + + it('should reset the value to zero', () => { + expect(Drupal.behaviors.ysDemo.applyAction(42, 'reset')).toBe(0); + expect(Drupal.behaviors.ysDemo.applyAction(-5, 'reset')).toBe(0); + }); + + it('should return the same value for unknown actions', () => { + expect(Drupal.behaviors.ysDemo.applyAction(7, 'unknown')).toBe(7); + }); + }); + + describe('removeUpdatedClassAfterDelay', () => { + beforeEach(() => { + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + it('should remove the updated class after 300ms', () => { + document.body.innerHTML = ''; + const element = document.querySelector('span'); + + Drupal.behaviors.ysDemo.removeUpdatedClassAfterDelay(element); + + expect(element.classList.contains('updated')).toBe(true); + jest.advanceTimersByTime(300); + expect(element.classList.contains('updated')).toBe(false); + }); + + it('should not remove the class before 300ms', () => { + document.body.innerHTML = ''; + const element = document.querySelector('span'); + + Drupal.behaviors.ysDemo.removeUpdatedClassAfterDelay(element); + + jest.advanceTimersByTime(299); + expect(element.classList.contains('updated')).toBe(true); + }); + }); + + describe('initCounterBlock', () => { + it('should initialize the counter display with 0', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('0'); + }); + + it('should initialize with saved localStorage value', () => { + localStorage.setItem('ys_counter_value', '15'); + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('15'); + }); + + it('should mark the block as processed', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const block = document.querySelector('[data-sw-demo-counter]'); + expect(block.classList.contains('sw-demo-counter-processed')).toBe(true); + }); + + it('should not re-process already processed blocks', () => { + document.body.innerHTML = createCounterBlockHtml(); + const block = document.querySelector('[data-sw-demo-counter]'); + block.classList.add('sw-demo-counter-processed'); + + const value = document.querySelector('[data-counter-value]'); + value.textContent = 'original'; + + Drupal.behaviors.ysDemo.initCounterBlock(document); + + expect(value.textContent).toBe('original'); + }); + + it('should increment counter on button click', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('1'); + }); + + it('should decrement counter on button click', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const decrementBtn = document.querySelector( + '[data-counter-action="decrement"]', + ); + decrementBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('-1'); + }); + + it('should reset counter on button click', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + incrementBtn.click(); + incrementBtn.click(); + + const resetBtn = document.querySelector('[data-counter-action="reset"]'); + resetBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('0'); + }); + + it('should save counter value to localStorage on click', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + incrementBtn.click(); + + expect(localStorage.getItem('ys_counter_value')).toBe('2'); + }); + + it('should add updated class on click for visual feedback', () => { + jest.useFakeTimers(); + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.classList.contains('updated')).toBe(true); + + jest.advanceTimersByTime(300); + expect(value.classList.contains('updated')).toBe(false); + jest.useRealTimers(); + }); + + it('should handle multiple counter blocks', () => { + document.body.innerHTML = ` +
+ 0 + +
+
+ 0 + +
+ `; + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const blocks = document.querySelectorAll('[data-sw-demo-counter]'); + expect(blocks[0].classList.contains('sw-demo-counter-processed')).toBe( + true, + ); + expect(blocks[1].classList.contains('sw-demo-counter-processed')).toBe( + true, + ); + }); + }); + + describe('attach', () => { + it('should call initCounterBlock with the context', () => { + document.body.innerHTML = createCounterBlockHtml(); + const spy = jest.spyOn(Drupal.behaviors.ysDemo, 'initCounterBlock'); + + Drupal.behaviors.ysDemo.attach(document); + + expect(spy).toHaveBeenCalledWith(document); + spy.mockRestore(); + }); + + it('should fully initialize when called as a behavior', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.attach(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('1'); + expect(localStorage.getItem('ys_counter_value')).toBe('1'); + }); + }); +}); From 11c5bd1d9ae26085654636bb73cffc09b36a3cdb Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 08:29:30 +1100 Subject: [PATCH 04/36] [#2394] Moved Jest CI step to build job and fixed duplicate yarn install. --- .circleci/config.yml | 18 +++++++++--------- .github/workflows/build-test-deploy.yml | 19 ++++++++++--------- .../installer/src/Prompts/Handlers/Tools.php | 3 --- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0675eb11e..5d44de827 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -151,9 +151,6 @@ jobs: #;< TOOL_ESLINT_STYLELINT docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" #;> TOOL_ESLINT_STYLELINT - #;< TOOL_JEST - docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" - #;> TOOL_JEST - run: name: Audit Composer packages @@ -203,12 +200,6 @@ jobs: command: docker compose exec -T cli bash -c "yarn run lint" || [ "${VORTEX_CI_NODEJS_LINT_IGNORE_FAILURE:-0}" -eq 1 ] #;> TOOL_ESLINT_STYLELINT - #;< TOOL_JEST - - run: - name: Test module code with Jest - command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] - #;> TOOL_JEST - #;< DRUPAL_THEME - run: name: Lint theme code with NodeJS linters @@ -372,6 +363,9 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \ if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" + #;< TOOL_JEST + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" + #;> TOOL_JEST - run: name: Provision site @@ -389,6 +383,12 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh no_output_timeout: 30m + #;< TOOL_JEST + - run: + name: Test with Jest + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + #;> TOOL_JEST + #;< TOOL_PHPUNIT - run: name: Test with PHPUnit diff --git a/.github/workflows/build-test-deploy.yml b/.github/workflows/build-test-deploy.yml index 3a3670de5..d317b73d1 100644 --- a/.github/workflows/build-test-deploy.yml +++ b/.github/workflows/build-test-deploy.yml @@ -134,9 +134,6 @@ jobs: #;< TOOL_ESLINT_STYLELINT docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" #;> TOOL_ESLINT_STYLELINT - #;< TOOL_JEST - docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" - #;> TOOL_JEST - name: Audit Composer packages run: docker compose exec -T cli composer audit @@ -186,12 +183,6 @@ jobs: continue-on-error: ${{ vars.VORTEX_CI_NODEJS_LINT_IGNORE_FAILURE == '1' }} #;> TOOL_ESLINT_STYLELINT - #;< TOOL_JEST - - name: Test module code with Jest - run: docker compose exec -T cli bash -c "yarn test" - continue-on-error: ${{ vars.VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE == '1' }} - #;> TOOL_JEST - #;< DRUPAL_THEME - name: Lint theme code with NodeJS linters if: ${{ vars.VORTEX_FRONTEND_BUILD_SKIP != '1' }} @@ -416,6 +407,9 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \ if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" + #;< TOOL_JEST + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" + #;> TOOL_JEST - name: Provision site run: | @@ -432,6 +426,13 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh timeout-minutes: 30 + #;< TOOL_JEST + - name: Test with Jest + if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} + run: docker compose exec -T cli bash -c "yarn test" + continue-on-error: ${{ vars.VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE == '1' }} + #;> TOOL_JEST + #;< TOOL_PHPUNIT - name: Test with PHPUnit if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} diff --git a/.vortex/installer/src/Prompts/Handlers/Tools.php b/.vortex/installer/src/Prompts/Handlers/Tools.php index 10c344ba7..68a384520 100644 --- a/.vortex/installer/src/Prompts/Handlers/Tools.php +++ b/.vortex/installer/src/Prompts/Handlers/Tools.php @@ -495,9 +495,6 @@ public static function getToolDefinitions(string $filter = 'all'): array { 'frontend_all' => [ 'tools' => [self::ESLINT, self::STYLELINT, self::JEST], 'files' => ['package.json', 'yarn.lock'], - 'ahoy' => [ - '/^\h*ahoy cli "yarn install --frozen-lockfile"\h*\n?/m', - ], ], ]; From 61a33dff95654e1c2084c8606512b70a9220a13c Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 08:30:00 +1100 Subject: [PATCH 05/36] Updated snapshots. --- .../.!!k2C/.docker/cli.dockerfile | 9 + .../.!!k2C/.docker/nginx-drupal.dockerfile | 9 + .../handler_process/.!!k2C/.env.local.example | 12 + .../handler_process/.!!k2C/phpunit.xml | 66 +++ .../handler_process/.!!k2C/web/-autoload.php | 0 .../custom/sw_demo/-sw_demo.deploy.php | 0 .../modules/custom/sw_demo/-sw_demo.info.yml | 0 .../custom/sw_demo/-sw_demo.libraries.yml | 0 .../modules/custom/sw_demo/-sw_demo.module | 0 .../install/-views.view.sw_demo_articles.yml | 0 .../modules/custom/sw_demo/css/-sw_demo.css | 0 .../web/modules/custom/sw_demo/js/-sw_demo.js | 0 .../src/Plugin/Block/-CounterBlock.php | 0 .../Plugin/GeneratedContent/Node/-Article.php | 0 .../GeneratedContent/Taxonomy/-Tags.php | 0 .../-sw-demo-counter-block.html.twig | 0 .../-CounterBlockTest.php | 0 .../tests/src/Kernel/-CounterBlockTest.php | 0 .../tests/src/Unit/-CounterBlockTest.php | 0 .../web/sites/default/-default.services.yml | 0 .../web/sites/default/-default.settings.php | 0 .../sites/default/-example.services.local.yml | 0 .../sites/default/-example.settings.local.php | 0 .../.!!k2C/web/sites/default/-services.yml | 0 .../.!!k2C/web/sites/default/-settings.php | 0 .../modules/-settings.automated_cron.php | 0 .../includes/modules/-settings.clamav.php | 0 .../modules/-settings.config_split.php | 0 .../-settings.environment_indicator.php | 0 .../includes/modules/-settings.fast404.php | 0 .../includes/modules/-settings.redis.php | 0 .../includes/modules/-settings.robotstxt.php | 0 .../includes/modules/-settings.seckit.php | 0 .../includes/modules/-settings.shield.php | 0 .../modules/-settings.stage_file_proxy.php | 0 .../includes/modules/-settings.sw_base.php | 0 .../includes/modules/-settings.system.php | 0 .../modules/-settings.trusted_hosts.php | 0 .../includes/modules/-settings.xmlsitemap.php | 0 .../providers/-settings.container.php | 0 .../includes/providers/-settings.gha.php | 0 .../.github/workflows/build-test-deploy.yml | 11 +- .../ciprovider_circleci/.circleci/config.yml | 5 + .../custom/sw_demo/js/-sw_demo.test.js | 0 .../custom/sw_demo/js/-sw_demo.test.js | 0 .../.circleci/config.yml | 5 + .../.circleci/config.yml | 5 + .../.github/workflows/build-test-deploy.yml | 2 +- .../.circleci/config.yml | 5 + .../handler_process/hosting_acquia/AGENTS.md | 2 +- .../modules/custom/sw_demo/js/sw_demo.js | 58 +- .../modules/custom/sw_demo/js/sw_demo.test.js | 270 +++++++++ .../hosting_acquia/jest.config.js | 9 + .../hosting_acquia/package.json | 4 +- .../custom/sw_demo/js/-sw_demo.test.js | 0 .../hosting_project_name___acquia/AGENTS.md | 2 +- .../modules/custom/sw_demo/js/sw_demo.js | 58 +- .../modules/custom/sw_demo/js/sw_demo.test.js | 270 +++++++++ .../jest.config.js | 9 + .../package.json | 4 +- .../custom/sw_demo/js/-sw_demo.test.js | 0 .../.circleci/config.yml | 5 + .../.github/workflows/build-test-deploy.yml | 2 +- .../.github/workflows/build-test-deploy.yml | 2 +- .../.github/workflows/build-test-deploy.yml | 2 +- .../.github/workflows/build-test-deploy.yml | 2 +- .../.github/workflows/build-test-deploy.yml | 2 +- .../.github/workflows/build-test-deploy.yml | 2 +- .../.circleci/config.yml | 5 + .../.github/workflows/build-test-deploy.yml | 2 +- .../custom/sw_demo/js/-sw_demo.test.js | 0 .../the_force_demo/js/the_force_demo.js | 58 +- .../the_force_demo/js/the_force_demo.test.js | 270 +++++++++ .../.github/workflows/build-test-deploy.yml | 2 +- .../timezone_circleci/.circleci/config.yml | 5 + .../.circleci/config.yml | 5 + .../tools_groups_no_be_tests/.ahoy.yml | 10 +- .../.github/workflows/build-test-deploy.yml | 12 +- .../tools_groups_no_be_tests/AGENTS.md | 5 +- .../.ahoy.yml | 10 +- .../.circleci/config.yml | 5 + .../AGENTS.md | 5 +- .../tools_groups_no_fe_lint/-jest.config.js | 0 .../tools_groups_no_fe_lint/.ahoy.yml | 23 +- .../.github/workflows/build-test-deploy.yml | 28 +- .../tools_groups_no_fe_lint/AGENTS.md | 10 + .../custom/sw_demo/js/-sw_demo.test.js | 0 .../-jest.config.js | 0 .../.ahoy.yml | 23 +- .../AGENTS.md | 10 + .../custom/sw_demo/js/-sw_demo.test.js | 0 .../-jest.config.js | 0 .../.ahoy.yml | 11 + .../.github/workflows/build-test-deploy.yml | 28 +- .../AGENTS.md | 10 + .../custom/sw_demo/js/-sw_demo.test.js | 0 .../-jest.config.js | 0 .../.ahoy.yml | 11 + .../AGENTS.md | 10 + .../custom/sw_demo/js/-sw_demo.test.js | 0 .../handler_process/tools_no_behat/.ahoy.yml | 8 +- .../.github/workflows/build-test-deploy.yml | 2 +- .../handler_process/tools_no_behat/AGENTS.md | 6 +- .../tools_no_behat_circleci/.ahoy.yml | 8 +- .../.circleci/config.yml | 5 + .../tools_no_behat_circleci/AGENTS.md | 6 +- .../tools_no_eslint/package.json | 9 +- .../.circleci/config.yml | 5 + .../tools_no_eslint_circleci/package.json | 9 +- .../tools_no_eslint_no_theme/package.json | 9 +- .../tools_no_jest/-jest.config.js | 0 .../handler_process/tools_no_jest/.ahoy.yml | 11 + .../.github/workflows/build-test-deploy.yml | 20 + .../handler_process/tools_no_jest/AGENTS.md | 10 + .../tools_no_jest/package.json | 15 + .../custom/sw_demo/js/-sw_demo.test.js | 0 .../tools_no_jest_circleci/-jest.config.js | 0 .../tools_no_jest_circleci/.ahoy.yml | 11 + .../.circleci/config.yml | 542 ++++++++++++++++++ .../.circleci/post-coverage-comment.sh | 79 +++ .../.github/workflows/-build-test-deploy.yml | 0 .../tools_no_jest_circleci/AGENTS.md | 10 + .../tools_no_jest_circleci/README.md | 9 + .../tools_no_jest_circleci/docs/ci.md | 12 + .../tools_no_jest_circleci/package.json | 15 + .../tests/phpunit/CircleCiConfigTest.php | 257 +++++++++ .../Drupal/EnvironmentSettingsTest.php | 12 + .../custom/sw_demo/js/-sw_demo.test.js | 0 .../includes/providers/-settings.gha.php | 0 .../includes/providers/settings.circleci.php | 17 + .../.circleci/config.yml | 5 + .../.circleci/config.yml | 5 + .../.circleci/config.yml | 5 + .../tools_no_phpunit/.ahoy.yml | 9 +- .../.github/workflows/build-test-deploy.yml | 6 +- .../tools_no_phpunit/AGENTS.md | 6 +- .../tools_no_phpunit_circleci/.ahoy.yml | 9 +- .../.circleci/config.yml | 5 + .../tools_no_phpunit_circleci/AGENTS.md | 6 +- .../.circleci/config.yml | 5 + .../tools_no_stylelint/package.json | 8 +- .../.circleci/config.yml | 5 + .../tools_no_stylelint_circleci/package.json | 8 +- .../tools_no_stylelint_no_theme/package.json | 8 +- .../tools_none/-jest.config.js | 0 .../handler_process/tools_none/.ahoy.yml | 15 +- .../.github/workflows/build-test-deploy.yml | 15 +- .../handler_process/tools_none/AGENTS.md | 5 +- .../custom/sw_demo/js/-sw_demo.test.js | 0 149 files changed, 2393 insertions(+), 209 deletions(-) create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/.docker/cli.dockerfile create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/.docker/nginx-drupal.dockerfile create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/.env.local.example create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/phpunit.xml create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/-autoload.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.deploy.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.info.yml create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.libraries.yml create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.module create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/config/install/-views.view.sw_demo_articles.yml create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/css/-sw_demo.css create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/js/-sw_demo.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/src/Plugin/Block/-CounterBlock.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/src/Plugin/GeneratedContent/Node/-Article.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/src/Plugin/GeneratedContent/Taxonomy/-Tags.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/templates/-sw-demo-counter-block.html.twig create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/tests/src/FunctionalJavascript/-CounterBlockTest.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/tests/src/Kernel/-CounterBlockTest.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/tests/src/Unit/-CounterBlockTest.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-default.services.yml create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-default.settings.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-example.services.local.yml create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-example.settings.local.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-services.yml create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-settings.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.automated_cron.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.clamav.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.config_split.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.environment_indicator.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.fast404.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.redis.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.robotstxt.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.seckit.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.shield.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.stage_file_proxy.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.sw_base.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.system.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.trusted_hosts.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.xmlsitemap.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/providers/-settings.container.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/providers/-settings.gha.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/custom_modules_no_demo/web/modules/custom/sw_demo/js/-sw_demo.test.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/custom_modules_none/web/modules/custom/sw_demo/js/-sw_demo.test.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/hosting_acquia/docroot/modules/custom/sw_demo/js/sw_demo.test.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/hosting_acquia/web/modules/custom/sw_demo/js/-sw_demo.test.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/docroot/modules/custom/sw_demo/js/sw_demo.test.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/web/modules/custom/sw_demo/js/-sw_demo.test.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/names/web/modules/custom/sw_demo/js/-sw_demo.test.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/names/web/modules/custom/the_force_demo/js/the_force_demo.test.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/-jest.config.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/AGENTS.md create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/web/modules/custom/sw_demo/js/-sw_demo.test.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_circleci/-jest.config.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_circleci/AGENTS.md create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_circleci/web/modules/custom/sw_demo/js/-sw_demo.test.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/-jest.config.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/AGENTS.md create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/web/modules/custom/sw_demo/js/-sw_demo.test.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme_circleci/-jest.config.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme_circleci/AGENTS.md create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme_circleci/web/modules/custom/sw_demo/js/-sw_demo.test.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest/-jest.config.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest/.ahoy.yml create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest/.github/workflows/build-test-deploy.yml create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest/AGENTS.md create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest/package.json create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest/web/modules/custom/sw_demo/js/-sw_demo.test.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/-jest.config.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/.ahoy.yml create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/.circleci/config.yml create mode 100755 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/.circleci/post-coverage-comment.sh create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/.github/workflows/-build-test-deploy.yml create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/AGENTS.md create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/README.md create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/docs/ci.md create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/package.json create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/tests/phpunit/CircleCiConfigTest.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/tests/phpunit/Drupal/EnvironmentSettingsTest.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/web/modules/custom/sw_demo/js/-sw_demo.test.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/web/sites/default/includes/providers/-settings.gha.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/web/sites/default/includes/providers/settings.circleci.php create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_none/-jest.config.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_none/web/modules/custom/sw_demo/js/-sw_demo.test.js diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/.docker/cli.dockerfile b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/.docker/cli.dockerfile new file mode 100644 index 000000000..399d0eee7 --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/.docker/cli.dockerfile @@ -0,0 +1,9 @@ +@@ -16,7 +16,7 @@ + ARG LAGOON_PR_HEAD_SHA="" + ENV LAGOON_PR_HEAD_SHA=${LAGOON_PR_HEAD_SHA} + +-ARG WEBROOT=web ++ARG WEBROOT=docroot + ENV WEBROOT=${WEBROOT} + + # Token is used to access private repositories. Not exposed as an environment diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/.docker/nginx-drupal.dockerfile b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/.docker/nginx-drupal.dockerfile new file mode 100644 index 000000000..7d6c276fd --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/.docker/nginx-drupal.dockerfile @@ -0,0 +1,9 @@ +@@ -14,7 +14,7 @@ + FROM uselagoon/nginx-drupal:__VERSION__ + + # Webroot is used for Nginx web root configuration. +-ARG WEBROOT=web ++ARG WEBROOT=docroot + ENV WEBROOT=${WEBROOT} + + RUN apk add --no-cache tzdata diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/.env.local.example b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/.env.local.example new file mode 100644 index 000000000..fa1beee41 --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/.env.local.example @@ -0,0 +1,12 @@ +@@ -32,3 +32,11 @@ + + # Always override existing downloaded DB dump. + VORTEX_DOWNLOAD_DB_FORCE=1 ++ ++# Database dump file sourced from Acquia. ++# Acquia Cloud API token: Acquia Cloud UI -> Account -> API tokens -> Create Token ++ ++# Acquia Cloud API key. ++VORTEX_ACQUIA_KEY= ++# Acquia Cloud API secret. ++VORTEX_ACQUIA_SECRET= diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/phpunit.xml b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/phpunit.xml new file mode 100644 index 000000000..ec09a29da --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/phpunit.xml @@ -0,0 +1,66 @@ +@@ -66,21 +66,21 @@ + + + tests/phpunit +- web/modules/custom/**/tests/src/Unit +- web/themes/custom/**/tests/src/Unit ++ docroot/modules/custom/**/tests/src/Unit ++ docroot/themes/custom/**/tests/src/Unit + + +- web/modules/custom/**/tests/src/Kernel +- web/themes/custom/**/tests/src/Kernel ++ docroot/modules/custom/**/tests/src/Kernel ++ docroot/themes/custom/**/tests/src/Kernel + + +- web/modules/custom/**/tests/src/Functional +- web/themes/custom/**/tests/src/Functional ++ docroot/modules/custom/**/tests/src/Functional ++ docroot/themes/custom/**/tests/src/Functional + + + +- web/modules/custom/**/tests/src/FunctionalJavascript +- web/themes/custom/**/tests/src/FunctionalJavascript ++ docroot/modules/custom/**/tests/src/FunctionalJavascript ++ docroot/themes/custom/**/tests/src/FunctionalJavascript + + + +@@ -101,17 +101,17 @@ + + + +- web/modules/custom +- web/themes/custom +- web/sites/default/includes +- web/sites/default/settings.php ++ docroot/modules/custom ++ docroot/themes/custom ++ docroot/sites/default/includes ++ docroot/sites/default/settings.php + + +- web/modules/custom +- web/modules/custom +- web/modules/custom/**/node_modules +- web/themes/custom +- web/themes/custom/**/node_modules ++ docroot/modules/custom ++ docroot/modules/custom ++ docroot/modules/custom/**/node_modules ++ docroot/themes/custom ++ docroot/themes/custom/**/node_modules + tests + + +@@ -127,7 +127,7 @@ + to DRUPAL_ROOT/sites/simpletest/browser_output. + @see https://www.drupal.org/project/drupal/issues/2992069 --> + +- ++ + + + diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/-autoload.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/-autoload.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.deploy.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.deploy.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.info.yml b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.info.yml new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.libraries.yml b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.libraries.yml new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.module b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.module new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/config/install/-views.view.sw_demo_articles.yml b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/config/install/-views.view.sw_demo_articles.yml new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/css/-sw_demo.css b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/css/-sw_demo.css new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/js/-sw_demo.js b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/js/-sw_demo.js new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/src/Plugin/Block/-CounterBlock.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/src/Plugin/Block/-CounterBlock.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/src/Plugin/GeneratedContent/Node/-Article.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/src/Plugin/GeneratedContent/Node/-Article.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/src/Plugin/GeneratedContent/Taxonomy/-Tags.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/src/Plugin/GeneratedContent/Taxonomy/-Tags.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/templates/-sw-demo-counter-block.html.twig b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/templates/-sw-demo-counter-block.html.twig new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/tests/src/FunctionalJavascript/-CounterBlockTest.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/tests/src/FunctionalJavascript/-CounterBlockTest.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/tests/src/Kernel/-CounterBlockTest.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/tests/src/Kernel/-CounterBlockTest.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/tests/src/Unit/-CounterBlockTest.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/tests/src/Unit/-CounterBlockTest.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-default.services.yml b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-default.services.yml new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-default.settings.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-default.settings.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-example.services.local.yml b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-example.services.local.yml new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-example.settings.local.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-example.settings.local.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-services.yml b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-services.yml new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-settings.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-settings.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.automated_cron.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.automated_cron.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.clamav.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.clamav.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.config_split.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.config_split.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.environment_indicator.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.environment_indicator.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.fast404.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.fast404.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.redis.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.redis.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.robotstxt.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.robotstxt.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.seckit.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.seckit.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.shield.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.shield.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.stage_file_proxy.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.stage_file_proxy.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.sw_base.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.sw_base.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.system.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.system.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.trusted_hosts.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.trusted_hosts.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.xmlsitemap.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.xmlsitemap.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/providers/-settings.container.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/providers/-settings.container.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/providers/-settings.gha.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/providers/-settings.gha.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/_baseline/.github/workflows/build-test-deploy.yml index 0d6837a4e..82f93f2df 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/.github/workflows/build-test-deploy.yml @@ -125,7 +125,6 @@ jobs: if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" - docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" - name: Audit Composer packages run: docker compose exec -T cli composer audit @@ -163,10 +162,6 @@ jobs: run: docker compose exec -T cli bash -c "yarn run lint" continue-on-error: ${{ vars.VORTEX_CI_NODEJS_LINT_IGNORE_FAILURE == '1' }} - - name: Test module code with Jest - run: docker compose exec -T cli bash -c "yarn test" - continue-on-error: ${{ vars.VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE == '1' }} - - name: Lint theme code with NodeJS linters if: ${{ vars.VORTEX_FRONTEND_BUILD_SKIP != '1' }} run: docker compose exec -T cli bash -c "yarn --cwd=\${WEBROOT}/themes/custom/\${DRUPAL_THEME} run lint" @@ -371,6 +366,7 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \ if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" - name: Provision site run: | @@ -381,6 +377,11 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh timeout-minutes: 30 + - name: Test with Jest + if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} + run: docker compose exec -T cli bash -c "yarn test" + continue-on-error: ${{ vars.VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE == '1' }} + - name: Test with PHPUnit if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} run: docker compose exec -T cli vendor/bin/phpunit diff --git a/.vortex/installer/tests/Fixtures/handler_process/ciprovider_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/ciprovider_circleci/.circleci/config.yml index d6fa3a565..16659c5c8 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/ciprovider_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/ciprovider_circleci/.circleci/config.yml @@ -325,6 +325,7 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \ if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" - run: name: Provision site @@ -336,6 +337,10 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh no_output_timeout: 30m + - run: + name: Test with Jest + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + - run: name: Test with PHPUnit command: | diff --git a/.vortex/installer/tests/Fixtures/handler_process/custom_modules_no_demo/web/modules/custom/sw_demo/js/-sw_demo.test.js b/.vortex/installer/tests/Fixtures/handler_process/custom_modules_no_demo/web/modules/custom/sw_demo/js/-sw_demo.test.js new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/custom_modules_none/web/modules/custom/sw_demo/js/-sw_demo.test.js b/.vortex/installer/tests/Fixtures/handler_process/custom_modules_none/web/modules/custom/sw_demo/js/-sw_demo.test.js new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/deploy_types_all_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/deploy_types_all_circleci/.circleci/config.yml index d6fa3a565..16659c5c8 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/deploy_types_all_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/deploy_types_all_circleci/.circleci/config.yml @@ -325,6 +325,7 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \ if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" - run: name: Provision site @@ -336,6 +337,10 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh no_output_timeout: 30m + - run: + name: Test with Jest + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + - run: name: Test with PHPUnit command: | diff --git a/.vortex/installer/tests/Fixtures/handler_process/deploy_types_none_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/deploy_types_none_circleci/.circleci/config.yml index 924d47e70..2198bd30a 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/deploy_types_none_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/deploy_types_none_circleci/.circleci/config.yml @@ -325,6 +325,7 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \ if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" - run: name: Provision site @@ -336,6 +337,10 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh no_output_timeout: 30m + - run: + name: Test with Jest + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + - run: name: Test with PHPUnit command: | diff --git a/.vortex/installer/tests/Fixtures/handler_process/deploy_types_none_gha/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/deploy_types_none_gha/.github/workflows/build-test-deploy.yml index 50fe45ac2..363683454 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/deploy_types_none_gha/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/deploy_types_none_gha/.github/workflows/build-test-deploy.yml @@ -1,4 +1,4 @@ -@@ -491,95 +491,3 @@ +@@ -497,95 +497,3 @@ timeout-minutes: 120 # Cancel the action after 15 minutes, regardless of whether a connection has been established. with: detached: true diff --git a/.vortex/installer/tests/Fixtures/handler_process/deps_updates_provider_ci_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/deps_updates_provider_ci_circleci/.circleci/config.yml index d6fa3a565..16659c5c8 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/deps_updates_provider_ci_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/deps_updates_provider_ci_circleci/.circleci/config.yml @@ -325,6 +325,7 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \ if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" - run: name: Provision site @@ -336,6 +337,10 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh no_output_timeout: 30m + - run: + name: Test with Jest + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + - run: name: Test with PHPUnit command: | diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/AGENTS.md b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/AGENTS.md index 144ce178e..bf8f6765d 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/AGENTS.md +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/AGENTS.md @@ -1,4 +1,4 @@ -@@ -79,8 +79,8 @@ +@@ -82,8 +82,8 @@ ## Key Directories diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/docroot/modules/custom/sw_demo/js/sw_demo.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/docroot/modules/custom/sw_demo/js/sw_demo.js index 3282266ce..886028723 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/docroot/modules/custom/sw_demo/js/sw_demo.js +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/docroot/modules/custom/sw_demo/js/sw_demo.js @@ -4,6 +4,8 @@ ((Drupal) => { Drupal.behaviors.ysDemo = { + storageKey: 'ys_counter_value', + attach(context) { this.initCounterBlock(context); }, @@ -17,7 +19,7 @@ initCounterBlock(context) { const counterBlocks = context.querySelectorAll('[data-sw-demo-counter]'); - counterBlocks.forEach(function processBlock(block) { + counterBlocks.forEach((block) => { // Skip if already processed. if (block.classList.contains('sw-demo-counter-processed')) { return; @@ -29,39 +31,24 @@ const buttons = block.querySelectorAll('[data-counter-action]'); // Load saved value from localStorage. - const storageKey = 'ys_counter_value'; - let currentValue = parseInt(localStorage.getItem(storageKey), 10) || 0; + let currentValue = this.getCounterValue(); valueElement.textContent = currentValue; // Add event listeners to buttons. - buttons.forEach(function processButton(button) { - button.addEventListener('click', function handleClick() { - const action = this.getAttribute('data-counter-action'); - - switch (action) { - case 'increment': - currentValue += 1; - break; - case 'decrement': - currentValue -= 1; - break; - case 'reset': - currentValue = 0; - break; - default: - // No action for unknown action types. - break; - } + buttons.forEach((button) => { + button.addEventListener('click', () => { + const action = button.getAttribute('data-counter-action'); + currentValue = this.applyAction(currentValue, action); - // Update display + // Update display. valueElement.textContent = currentValue; // Save to localStorage. - localStorage.setItem(storageKey, currentValue.toString()); + localStorage.setItem(this.storageKey, currentValue.toString()); // Add visual feedback. valueElement.classList.add('updated'); - Drupal.behaviors.ysDemo.removeUpdatedClassAfterDelay(valueElement); + this.removeUpdatedClassAfterDelay(valueElement); // Log action for debugging. // eslint-disable-next-line no-console @@ -71,6 +58,26 @@ }); }, + /** + * Apply a counter action and return the new value. + * + * @param {number} value The current counter value. + * @param {string} action The action to apply. + * @return {number} The new counter value. + */ + applyAction(value, action) { + switch (action) { + case 'increment': + return value + 1; + case 'decrement': + return value - 1; + case 'reset': + return 0; + default: + return value; + } + }, + /** * Remove updated class after a delay for visual feedback. * @@ -88,8 +95,7 @@ * @return {number} The current counter value, or 0 if not set. */ getCounterValue() { - const storageKey = 'ys_counter_value'; - return parseInt(localStorage.getItem(storageKey), 10) || 0; + return parseInt(localStorage.getItem(this.storageKey), 10) || 0; }, }; })(Drupal); diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/docroot/modules/custom/sw_demo/js/sw_demo.test.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/docroot/modules/custom/sw_demo/js/sw_demo.test.js new file mode 100644 index 000000000..244df74d2 --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/docroot/modules/custom/sw_demo/js/sw_demo.test.js @@ -0,0 +1,270 @@ +const fs = require('fs'); +const path = require('path'); + +describe('Drupal.behaviors.ysDemo', () => { + beforeEach(() => { + localStorage.clear(); + global.Drupal = { behaviors: {} }; + + const filePath = path.resolve(__dirname, 'sw_demo.js'); + const code = fs.readFileSync(filePath, 'utf8'); + eval(code); + }); + + afterEach(() => { + delete global.Drupal; + }); + + function createCounterBlockHtml() { + return ` +
+ 0 + + + +
+ `; + } + + describe('storageKey', () => { + it('should have the expected storage key', () => { + expect(Drupal.behaviors.ysDemo.storageKey).toBe('ys_counter_value'); + }); + }); + + describe('getCounterValue', () => { + it('should return 0 when localStorage is empty', () => { + expect(Drupal.behaviors.ysDemo.getCounterValue()).toBe(0); + }); + + it('should return the stored value from localStorage', () => { + localStorage.setItem('ys_counter_value', '42'); + expect(Drupal.behaviors.ysDemo.getCounterValue()).toBe(42); + }); + + it('should return 0 for non-numeric localStorage values', () => { + localStorage.setItem('ys_counter_value', 'invalid'); + expect(Drupal.behaviors.ysDemo.getCounterValue()).toBe(0); + }); + + it('should return negative values correctly', () => { + localStorage.setItem('ys_counter_value', '-5'); + expect(Drupal.behaviors.ysDemo.getCounterValue()).toBe(-5); + }); + }); + + describe('applyAction', () => { + it('should increment the value', () => { + expect(Drupal.behaviors.ysDemo.applyAction(0, 'increment')).toBe(1); + expect(Drupal.behaviors.ysDemo.applyAction(10, 'increment')).toBe(11); + }); + + it('should decrement the value', () => { + expect(Drupal.behaviors.ysDemo.applyAction(0, 'decrement')).toBe(-1); + expect(Drupal.behaviors.ysDemo.applyAction(5, 'decrement')).toBe(4); + }); + + it('should reset the value to zero', () => { + expect(Drupal.behaviors.ysDemo.applyAction(42, 'reset')).toBe(0); + expect(Drupal.behaviors.ysDemo.applyAction(-5, 'reset')).toBe(0); + }); + + it('should return the same value for unknown actions', () => { + expect(Drupal.behaviors.ysDemo.applyAction(7, 'unknown')).toBe(7); + }); + }); + + describe('removeUpdatedClassAfterDelay', () => { + beforeEach(() => { + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + it('should remove the updated class after 300ms', () => { + document.body.innerHTML = ''; + const element = document.querySelector('span'); + + Drupal.behaviors.ysDemo.removeUpdatedClassAfterDelay(element); + + expect(element.classList.contains('updated')).toBe(true); + jest.advanceTimersByTime(300); + expect(element.classList.contains('updated')).toBe(false); + }); + + it('should not remove the class before 300ms', () => { + document.body.innerHTML = ''; + const element = document.querySelector('span'); + + Drupal.behaviors.ysDemo.removeUpdatedClassAfterDelay(element); + + jest.advanceTimersByTime(299); + expect(element.classList.contains('updated')).toBe(true); + }); + }); + + describe('initCounterBlock', () => { + it('should initialize the counter display with 0', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('0'); + }); + + it('should initialize with saved localStorage value', () => { + localStorage.setItem('ys_counter_value', '15'); + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('15'); + }); + + it('should mark the block as processed', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const block = document.querySelector('[data-sw-demo-counter]'); + expect(block.classList.contains('sw-demo-counter-processed')).toBe(true); + }); + + it('should not re-process already processed blocks', () => { + document.body.innerHTML = createCounterBlockHtml(); + const block = document.querySelector('[data-sw-demo-counter]'); + block.classList.add('sw-demo-counter-processed'); + + const value = document.querySelector('[data-counter-value]'); + value.textContent = 'original'; + + Drupal.behaviors.ysDemo.initCounterBlock(document); + + expect(value.textContent).toBe('original'); + }); + + it('should increment counter on button click', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('1'); + }); + + it('should decrement counter on button click', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const decrementBtn = document.querySelector( + '[data-counter-action="decrement"]', + ); + decrementBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('-1'); + }); + + it('should reset counter on button click', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + incrementBtn.click(); + incrementBtn.click(); + + const resetBtn = document.querySelector('[data-counter-action="reset"]'); + resetBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('0'); + }); + + it('should save counter value to localStorage on click', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + incrementBtn.click(); + + expect(localStorage.getItem('ys_counter_value')).toBe('2'); + }); + + it('should add updated class on click for visual feedback', () => { + jest.useFakeTimers(); + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.classList.contains('updated')).toBe(true); + + jest.advanceTimersByTime(300); + expect(value.classList.contains('updated')).toBe(false); + jest.useRealTimers(); + }); + + it('should handle multiple counter blocks', () => { + document.body.innerHTML = ` +
+ 0 + +
+
+ 0 + +
+ `; + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const blocks = document.querySelectorAll('[data-sw-demo-counter]'); + expect(blocks[0].classList.contains('sw-demo-counter-processed')).toBe( + true, + ); + expect(blocks[1].classList.contains('sw-demo-counter-processed')).toBe( + true, + ); + }); + }); + + describe('attach', () => { + it('should call initCounterBlock with the context', () => { + document.body.innerHTML = createCounterBlockHtml(); + const spy = jest.spyOn(Drupal.behaviors.ysDemo, 'initCounterBlock'); + + Drupal.behaviors.ysDemo.attach(document); + + expect(spy).toHaveBeenCalledWith(document); + spy.mockRestore(); + }); + + it('should fully initialize when called as a behavior', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.attach(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('1'); + expect(localStorage.getItem('ys_counter_value')).toBe('1'); + }); + }); +}); diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js new file mode 100644 index 000000000..5b5f2913d --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js @@ -0,0 +1,9 @@ +@@ -4,7 +4,7 @@ + // Discover js/ directories in custom modules, resolving symlinks to real + // paths. Jest resolves symlinks internally, so roots must use real paths + // for test files to be matched. +-const dirs = ['web/modules/custom']; ++const dirs = ['docroot/modules/custom']; + const roots = []; + + dirs.forEach((dir) => { diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/package.json b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/package.json index a31d3de73..40c40de58 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/package.json @@ -11,6 +11,6 @@ - "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", + "lint-fix-js": "eslint docroot/modules/custom --ext .js --no-error-on-unmatched-pattern --fix", + "lint-fix-css": "stylelint --allow-empty-input \"docroot/modules/custom/**/*.css\" --fix", - "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css" + "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", + "test": "jest" }, - "devDependencies": { diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/web/modules/custom/sw_demo/js/-sw_demo.test.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/web/modules/custom/sw_demo/js/-sw_demo.test.js new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/AGENTS.md b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/AGENTS.md index 144ce178e..bf8f6765d 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/AGENTS.md +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/AGENTS.md @@ -1,4 +1,4 @@ -@@ -79,8 +79,8 @@ +@@ -82,8 +82,8 @@ ## Key Directories diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/docroot/modules/custom/sw_demo/js/sw_demo.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/docroot/modules/custom/sw_demo/js/sw_demo.js index 3282266ce..886028723 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/docroot/modules/custom/sw_demo/js/sw_demo.js +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/docroot/modules/custom/sw_demo/js/sw_demo.js @@ -4,6 +4,8 @@ ((Drupal) => { Drupal.behaviors.ysDemo = { + storageKey: 'ys_counter_value', + attach(context) { this.initCounterBlock(context); }, @@ -17,7 +19,7 @@ initCounterBlock(context) { const counterBlocks = context.querySelectorAll('[data-sw-demo-counter]'); - counterBlocks.forEach(function processBlock(block) { + counterBlocks.forEach((block) => { // Skip if already processed. if (block.classList.contains('sw-demo-counter-processed')) { return; @@ -29,39 +31,24 @@ const buttons = block.querySelectorAll('[data-counter-action]'); // Load saved value from localStorage. - const storageKey = 'ys_counter_value'; - let currentValue = parseInt(localStorage.getItem(storageKey), 10) || 0; + let currentValue = this.getCounterValue(); valueElement.textContent = currentValue; // Add event listeners to buttons. - buttons.forEach(function processButton(button) { - button.addEventListener('click', function handleClick() { - const action = this.getAttribute('data-counter-action'); - - switch (action) { - case 'increment': - currentValue += 1; - break; - case 'decrement': - currentValue -= 1; - break; - case 'reset': - currentValue = 0; - break; - default: - // No action for unknown action types. - break; - } + buttons.forEach((button) => { + button.addEventListener('click', () => { + const action = button.getAttribute('data-counter-action'); + currentValue = this.applyAction(currentValue, action); - // Update display + // Update display. valueElement.textContent = currentValue; // Save to localStorage. - localStorage.setItem(storageKey, currentValue.toString()); + localStorage.setItem(this.storageKey, currentValue.toString()); // Add visual feedback. valueElement.classList.add('updated'); - Drupal.behaviors.ysDemo.removeUpdatedClassAfterDelay(valueElement); + this.removeUpdatedClassAfterDelay(valueElement); // Log action for debugging. // eslint-disable-next-line no-console @@ -71,6 +58,26 @@ }); }, + /** + * Apply a counter action and return the new value. + * + * @param {number} value The current counter value. + * @param {string} action The action to apply. + * @return {number} The new counter value. + */ + applyAction(value, action) { + switch (action) { + case 'increment': + return value + 1; + case 'decrement': + return value - 1; + case 'reset': + return 0; + default: + return value; + } + }, + /** * Remove updated class after a delay for visual feedback. * @@ -88,8 +95,7 @@ * @return {number} The current counter value, or 0 if not set. */ getCounterValue() { - const storageKey = 'ys_counter_value'; - return parseInt(localStorage.getItem(storageKey), 10) || 0; + return parseInt(localStorage.getItem(this.storageKey), 10) || 0; }, }; })(Drupal); diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/docroot/modules/custom/sw_demo/js/sw_demo.test.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/docroot/modules/custom/sw_demo/js/sw_demo.test.js new file mode 100644 index 000000000..244df74d2 --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/docroot/modules/custom/sw_demo/js/sw_demo.test.js @@ -0,0 +1,270 @@ +const fs = require('fs'); +const path = require('path'); + +describe('Drupal.behaviors.ysDemo', () => { + beforeEach(() => { + localStorage.clear(); + global.Drupal = { behaviors: {} }; + + const filePath = path.resolve(__dirname, 'sw_demo.js'); + const code = fs.readFileSync(filePath, 'utf8'); + eval(code); + }); + + afterEach(() => { + delete global.Drupal; + }); + + function createCounterBlockHtml() { + return ` +
+ 0 + + + +
+ `; + } + + describe('storageKey', () => { + it('should have the expected storage key', () => { + expect(Drupal.behaviors.ysDemo.storageKey).toBe('ys_counter_value'); + }); + }); + + describe('getCounterValue', () => { + it('should return 0 when localStorage is empty', () => { + expect(Drupal.behaviors.ysDemo.getCounterValue()).toBe(0); + }); + + it('should return the stored value from localStorage', () => { + localStorage.setItem('ys_counter_value', '42'); + expect(Drupal.behaviors.ysDemo.getCounterValue()).toBe(42); + }); + + it('should return 0 for non-numeric localStorage values', () => { + localStorage.setItem('ys_counter_value', 'invalid'); + expect(Drupal.behaviors.ysDemo.getCounterValue()).toBe(0); + }); + + it('should return negative values correctly', () => { + localStorage.setItem('ys_counter_value', '-5'); + expect(Drupal.behaviors.ysDemo.getCounterValue()).toBe(-5); + }); + }); + + describe('applyAction', () => { + it('should increment the value', () => { + expect(Drupal.behaviors.ysDemo.applyAction(0, 'increment')).toBe(1); + expect(Drupal.behaviors.ysDemo.applyAction(10, 'increment')).toBe(11); + }); + + it('should decrement the value', () => { + expect(Drupal.behaviors.ysDemo.applyAction(0, 'decrement')).toBe(-1); + expect(Drupal.behaviors.ysDemo.applyAction(5, 'decrement')).toBe(4); + }); + + it('should reset the value to zero', () => { + expect(Drupal.behaviors.ysDemo.applyAction(42, 'reset')).toBe(0); + expect(Drupal.behaviors.ysDemo.applyAction(-5, 'reset')).toBe(0); + }); + + it('should return the same value for unknown actions', () => { + expect(Drupal.behaviors.ysDemo.applyAction(7, 'unknown')).toBe(7); + }); + }); + + describe('removeUpdatedClassAfterDelay', () => { + beforeEach(() => { + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + it('should remove the updated class after 300ms', () => { + document.body.innerHTML = ''; + const element = document.querySelector('span'); + + Drupal.behaviors.ysDemo.removeUpdatedClassAfterDelay(element); + + expect(element.classList.contains('updated')).toBe(true); + jest.advanceTimersByTime(300); + expect(element.classList.contains('updated')).toBe(false); + }); + + it('should not remove the class before 300ms', () => { + document.body.innerHTML = ''; + const element = document.querySelector('span'); + + Drupal.behaviors.ysDemo.removeUpdatedClassAfterDelay(element); + + jest.advanceTimersByTime(299); + expect(element.classList.contains('updated')).toBe(true); + }); + }); + + describe('initCounterBlock', () => { + it('should initialize the counter display with 0', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('0'); + }); + + it('should initialize with saved localStorage value', () => { + localStorage.setItem('ys_counter_value', '15'); + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('15'); + }); + + it('should mark the block as processed', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const block = document.querySelector('[data-sw-demo-counter]'); + expect(block.classList.contains('sw-demo-counter-processed')).toBe(true); + }); + + it('should not re-process already processed blocks', () => { + document.body.innerHTML = createCounterBlockHtml(); + const block = document.querySelector('[data-sw-demo-counter]'); + block.classList.add('sw-demo-counter-processed'); + + const value = document.querySelector('[data-counter-value]'); + value.textContent = 'original'; + + Drupal.behaviors.ysDemo.initCounterBlock(document); + + expect(value.textContent).toBe('original'); + }); + + it('should increment counter on button click', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('1'); + }); + + it('should decrement counter on button click', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const decrementBtn = document.querySelector( + '[data-counter-action="decrement"]', + ); + decrementBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('-1'); + }); + + it('should reset counter on button click', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + incrementBtn.click(); + incrementBtn.click(); + + const resetBtn = document.querySelector('[data-counter-action="reset"]'); + resetBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('0'); + }); + + it('should save counter value to localStorage on click', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + incrementBtn.click(); + + expect(localStorage.getItem('ys_counter_value')).toBe('2'); + }); + + it('should add updated class on click for visual feedback', () => { + jest.useFakeTimers(); + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.classList.contains('updated')).toBe(true); + + jest.advanceTimersByTime(300); + expect(value.classList.contains('updated')).toBe(false); + jest.useRealTimers(); + }); + + it('should handle multiple counter blocks', () => { + document.body.innerHTML = ` +
+ 0 + +
+
+ 0 + +
+ `; + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const blocks = document.querySelectorAll('[data-sw-demo-counter]'); + expect(blocks[0].classList.contains('sw-demo-counter-processed')).toBe( + true, + ); + expect(blocks[1].classList.contains('sw-demo-counter-processed')).toBe( + true, + ); + }); + }); + + describe('attach', () => { + it('should call initCounterBlock with the context', () => { + document.body.innerHTML = createCounterBlockHtml(); + const spy = jest.spyOn(Drupal.behaviors.ysDemo, 'initCounterBlock'); + + Drupal.behaviors.ysDemo.attach(document); + + expect(spy).toHaveBeenCalledWith(document); + spy.mockRestore(); + }); + + it('should fully initialize when called as a behavior', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.attach(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('1'); + expect(localStorage.getItem('ys_counter_value')).toBe('1'); + }); + }); +}); diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js new file mode 100644 index 000000000..5b5f2913d --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js @@ -0,0 +1,9 @@ +@@ -4,7 +4,7 @@ + // Discover js/ directories in custom modules, resolving symlinks to real + // paths. Jest resolves symlinks internally, so roots must use real paths + // for test files to be matched. +-const dirs = ['web/modules/custom']; ++const dirs = ['docroot/modules/custom']; + const roots = []; + + dirs.forEach((dir) => { diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/package.json b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/package.json index a31d3de73..40c40de58 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/package.json @@ -11,6 +11,6 @@ - "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", + "lint-fix-js": "eslint docroot/modules/custom --ext .js --no-error-on-unmatched-pattern --fix", + "lint-fix-css": "stylelint --allow-empty-input \"docroot/modules/custom/**/*.css\" --fix", - "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css" + "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", + "test": "jest" }, - "devDependencies": { diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/web/modules/custom/sw_demo/js/-sw_demo.test.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/web/modules/custom/sw_demo/js/-sw_demo.test.js new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/migration_disabled_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/migration_disabled_circleci/.circleci/config.yml index d6fa3a565..16659c5c8 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/migration_disabled_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/migration_disabled_circleci/.circleci/config.yml @@ -325,6 +325,7 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \ if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" - run: name: Provision site @@ -336,6 +337,10 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh no_output_timeout: 30m + - run: + name: Test with Jest + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + - run: name: Test with PHPUnit command: | diff --git a/.vortex/installer/tests/Fixtures/handler_process/migration_download_source_acquia/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/migration_download_source_acquia/.github/workflows/build-test-deploy.yml index ef6849b63..37d96c1a1 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/migration_download_source_acquia/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/migration_download_source_acquia/.github/workflows/build-test-deploy.yml @@ -8,7 +8,7 @@ - name: Export DB run: | if [ ! -f /tmp/download-db-success ]; then echo "==> Database download semaphore file is missing. DB export will not proceed."; exit 0; fi -@@ -372,6 +375,10 @@ +@@ -373,6 +376,10 @@ if [ -f .data/db.sql ]; then docker compose exec cli mkdir -p .data docker compose cp -L .data/db.sql cli:/app/.data/db.sql diff --git a/.vortex/installer/tests/Fixtures/handler_process/migration_download_source_ftp/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/migration_download_source_ftp/.github/workflows/build-test-deploy.yml index ef6849b63..37d96c1a1 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/migration_download_source_ftp/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/migration_download_source_ftp/.github/workflows/build-test-deploy.yml @@ -8,7 +8,7 @@ - name: Export DB run: | if [ ! -f /tmp/download-db-success ]; then echo "==> Database download semaphore file is missing. DB export will not proceed."; exit 0; fi -@@ -372,6 +375,10 @@ +@@ -373,6 +376,10 @@ if [ -f .data/db.sql ]; then docker compose exec cli mkdir -p .data docker compose cp -L .data/db.sql cli:/app/.data/db.sql diff --git a/.vortex/installer/tests/Fixtures/handler_process/migration_download_source_lagoon/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/migration_download_source_lagoon/.github/workflows/build-test-deploy.yml index ef6849b63..37d96c1a1 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/migration_download_source_lagoon/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/migration_download_source_lagoon/.github/workflows/build-test-deploy.yml @@ -8,7 +8,7 @@ - name: Export DB run: | if [ ! -f /tmp/download-db-success ]; then echo "==> Database download semaphore file is missing. DB export will not proceed."; exit 0; fi -@@ -372,6 +375,10 @@ +@@ -373,6 +376,10 @@ if [ -f .data/db.sql ]; then docker compose exec cli mkdir -p .data docker compose cp -L .data/db.sql cli:/app/.data/db.sql diff --git a/.vortex/installer/tests/Fixtures/handler_process/migration_download_source_s3/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/migration_download_source_s3/.github/workflows/build-test-deploy.yml index ef6849b63..37d96c1a1 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/migration_download_source_s3/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/migration_download_source_s3/.github/workflows/build-test-deploy.yml @@ -8,7 +8,7 @@ - name: Export DB run: | if [ ! -f /tmp/download-db-success ]; then echo "==> Database download semaphore file is missing. DB export will not proceed."; exit 0; fi -@@ -372,6 +375,10 @@ +@@ -373,6 +376,10 @@ if [ -f .data/db.sql ]; then docker compose exec cli mkdir -p .data docker compose cp -L .data/db.sql cli:/app/.data/db.sql diff --git a/.vortex/installer/tests/Fixtures/handler_process/migration_download_source_url/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/migration_download_source_url/.github/workflows/build-test-deploy.yml index ef6849b63..37d96c1a1 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/migration_download_source_url/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/migration_download_source_url/.github/workflows/build-test-deploy.yml @@ -8,7 +8,7 @@ - name: Export DB run: | if [ ! -f /tmp/download-db-success ]; then echo "==> Database download semaphore file is missing. DB export will not proceed."; exit 0; fi -@@ -372,6 +375,10 @@ +@@ -373,6 +376,10 @@ if [ -f .data/db.sql ]; then docker compose exec cli mkdir -p .data docker compose cp -L .data/db.sql cli:/app/.data/db.sql diff --git a/.vortex/installer/tests/Fixtures/handler_process/migration_enabled/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/migration_enabled/.github/workflows/build-test-deploy.yml index ef6849b63..37d96c1a1 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/migration_enabled/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/migration_enabled/.github/workflows/build-test-deploy.yml @@ -8,7 +8,7 @@ - name: Export DB run: | if [ ! -f /tmp/download-db-success ]; then echo "==> Database download semaphore file is missing. DB export will not proceed."; exit 0; fi -@@ -372,6 +375,10 @@ +@@ -373,6 +376,10 @@ if [ -f .data/db.sql ]; then docker compose exec cli mkdir -p .data docker compose cp -L .data/db.sql cli:/app/.data/db.sql diff --git a/.vortex/installer/tests/Fixtures/handler_process/migration_enabled_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/migration_enabled_circleci/.circleci/config.yml index 93f6a46bf..f36cc4b94 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/migration_enabled_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/migration_enabled_circleci/.circleci/config.yml @@ -330,6 +330,7 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \ if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" - run: name: Provision site @@ -345,6 +346,10 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh no_output_timeout: 30m + - run: + name: Test with Jest + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + - run: name: Test with PHPUnit command: | diff --git a/.vortex/installer/tests/Fixtures/handler_process/migration_enabled_lagoon/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/migration_enabled_lagoon/.github/workflows/build-test-deploy.yml index ef6849b63..37d96c1a1 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/migration_enabled_lagoon/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/migration_enabled_lagoon/.github/workflows/build-test-deploy.yml @@ -8,7 +8,7 @@ - name: Export DB run: | if [ ! -f /tmp/download-db-success ]; then echo "==> Database download semaphore file is missing. DB export will not proceed."; exit 0; fi -@@ -372,6 +375,10 @@ +@@ -373,6 +376,10 @@ if [ -f .data/db.sql ]; then docker compose exec cli mkdir -p .data docker compose cp -L .data/db.sql cli:/app/.data/db.sql diff --git a/.vortex/installer/tests/Fixtures/handler_process/names/web/modules/custom/sw_demo/js/-sw_demo.test.js b/.vortex/installer/tests/Fixtures/handler_process/names/web/modules/custom/sw_demo/js/-sw_demo.test.js new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/names/web/modules/custom/the_force_demo/js/the_force_demo.js b/.vortex/installer/tests/Fixtures/handler_process/names/web/modules/custom/the_force_demo/js/the_force_demo.js index e8ec713c4..e17060cb4 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/names/web/modules/custom/the_force_demo/js/the_force_demo.js +++ b/.vortex/installer/tests/Fixtures/handler_process/names/web/modules/custom/the_force_demo/js/the_force_demo.js @@ -4,6 +4,8 @@ ((Drupal) => { Drupal.behaviors.ysDemo = { + storageKey: 'ys_counter_value', + attach(context) { this.initCounterBlock(context); }, @@ -17,7 +19,7 @@ initCounterBlock(context) { const counterBlocks = context.querySelectorAll('[data-the-force-demo-counter]'); - counterBlocks.forEach(function processBlock(block) { + counterBlocks.forEach((block) => { // Skip if already processed. if (block.classList.contains('the-force-demo-counter-processed')) { return; @@ -29,39 +31,24 @@ const buttons = block.querySelectorAll('[data-counter-action]'); // Load saved value from localStorage. - const storageKey = 'ys_counter_value'; - let currentValue = parseInt(localStorage.getItem(storageKey), 10) || 0; + let currentValue = this.getCounterValue(); valueElement.textContent = currentValue; // Add event listeners to buttons. - buttons.forEach(function processButton(button) { - button.addEventListener('click', function handleClick() { - const action = this.getAttribute('data-counter-action'); - - switch (action) { - case 'increment': - currentValue += 1; - break; - case 'decrement': - currentValue -= 1; - break; - case 'reset': - currentValue = 0; - break; - default: - // No action for unknown action types. - break; - } + buttons.forEach((button) => { + button.addEventListener('click', () => { + const action = button.getAttribute('data-counter-action'); + currentValue = this.applyAction(currentValue, action); - // Update display + // Update display. valueElement.textContent = currentValue; // Save to localStorage. - localStorage.setItem(storageKey, currentValue.toString()); + localStorage.setItem(this.storageKey, currentValue.toString()); // Add visual feedback. valueElement.classList.add('updated'); - Drupal.behaviors.ysDemo.removeUpdatedClassAfterDelay(valueElement); + this.removeUpdatedClassAfterDelay(valueElement); // Log action for debugging. // eslint-disable-next-line no-console @@ -71,6 +58,26 @@ }); }, + /** + * Apply a counter action and return the new value. + * + * @param {number} value The current counter value. + * @param {string} action The action to apply. + * @return {number} The new counter value. + */ + applyAction(value, action) { + switch (action) { + case 'increment': + return value + 1; + case 'decrement': + return value - 1; + case 'reset': + return 0; + default: + return value; + } + }, + /** * Remove updated class after a delay for visual feedback. * @@ -88,8 +95,7 @@ * @return {number} The current counter value, or 0 if not set. */ getCounterValue() { - const storageKey = 'ys_counter_value'; - return parseInt(localStorage.getItem(storageKey), 10) || 0; + return parseInt(localStorage.getItem(this.storageKey), 10) || 0; }, }; })(Drupal); diff --git a/.vortex/installer/tests/Fixtures/handler_process/names/web/modules/custom/the_force_demo/js/the_force_demo.test.js b/.vortex/installer/tests/Fixtures/handler_process/names/web/modules/custom/the_force_demo/js/the_force_demo.test.js new file mode 100644 index 000000000..5ecf29f9c --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/names/web/modules/custom/the_force_demo/js/the_force_demo.test.js @@ -0,0 +1,270 @@ +const fs = require('fs'); +const path = require('path'); + +describe('Drupal.behaviors.ysDemo', () => { + beforeEach(() => { + localStorage.clear(); + global.Drupal = { behaviors: {} }; + + const filePath = path.resolve(__dirname, 'the_force_demo.js'); + const code = fs.readFileSync(filePath, 'utf8'); + eval(code); + }); + + afterEach(() => { + delete global.Drupal; + }); + + function createCounterBlockHtml() { + return ` +
+ 0 + + + +
+ `; + } + + describe('storageKey', () => { + it('should have the expected storage key', () => { + expect(Drupal.behaviors.ysDemo.storageKey).toBe('ys_counter_value'); + }); + }); + + describe('getCounterValue', () => { + it('should return 0 when localStorage is empty', () => { + expect(Drupal.behaviors.ysDemo.getCounterValue()).toBe(0); + }); + + it('should return the stored value from localStorage', () => { + localStorage.setItem('ys_counter_value', '42'); + expect(Drupal.behaviors.ysDemo.getCounterValue()).toBe(42); + }); + + it('should return 0 for non-numeric localStorage values', () => { + localStorage.setItem('ys_counter_value', 'invalid'); + expect(Drupal.behaviors.ysDemo.getCounterValue()).toBe(0); + }); + + it('should return negative values correctly', () => { + localStorage.setItem('ys_counter_value', '-5'); + expect(Drupal.behaviors.ysDemo.getCounterValue()).toBe(-5); + }); + }); + + describe('applyAction', () => { + it('should increment the value', () => { + expect(Drupal.behaviors.ysDemo.applyAction(0, 'increment')).toBe(1); + expect(Drupal.behaviors.ysDemo.applyAction(10, 'increment')).toBe(11); + }); + + it('should decrement the value', () => { + expect(Drupal.behaviors.ysDemo.applyAction(0, 'decrement')).toBe(-1); + expect(Drupal.behaviors.ysDemo.applyAction(5, 'decrement')).toBe(4); + }); + + it('should reset the value to zero', () => { + expect(Drupal.behaviors.ysDemo.applyAction(42, 'reset')).toBe(0); + expect(Drupal.behaviors.ysDemo.applyAction(-5, 'reset')).toBe(0); + }); + + it('should return the same value for unknown actions', () => { + expect(Drupal.behaviors.ysDemo.applyAction(7, 'unknown')).toBe(7); + }); + }); + + describe('removeUpdatedClassAfterDelay', () => { + beforeEach(() => { + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + it('should remove the updated class after 300ms', () => { + document.body.innerHTML = ''; + const element = document.querySelector('span'); + + Drupal.behaviors.ysDemo.removeUpdatedClassAfterDelay(element); + + expect(element.classList.contains('updated')).toBe(true); + jest.advanceTimersByTime(300); + expect(element.classList.contains('updated')).toBe(false); + }); + + it('should not remove the class before 300ms', () => { + document.body.innerHTML = ''; + const element = document.querySelector('span'); + + Drupal.behaviors.ysDemo.removeUpdatedClassAfterDelay(element); + + jest.advanceTimersByTime(299); + expect(element.classList.contains('updated')).toBe(true); + }); + }); + + describe('initCounterBlock', () => { + it('should initialize the counter display with 0', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('0'); + }); + + it('should initialize with saved localStorage value', () => { + localStorage.setItem('ys_counter_value', '15'); + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('15'); + }); + + it('should mark the block as processed', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const block = document.querySelector('[data-the-force-demo-counter]'); + expect(block.classList.contains('the-force-demo-counter-processed')).toBe(true); + }); + + it('should not re-process already processed blocks', () => { + document.body.innerHTML = createCounterBlockHtml(); + const block = document.querySelector('[data-the-force-demo-counter]'); + block.classList.add('the-force-demo-counter-processed'); + + const value = document.querySelector('[data-counter-value]'); + value.textContent = 'original'; + + Drupal.behaviors.ysDemo.initCounterBlock(document); + + expect(value.textContent).toBe('original'); + }); + + it('should increment counter on button click', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('1'); + }); + + it('should decrement counter on button click', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const decrementBtn = document.querySelector( + '[data-counter-action="decrement"]', + ); + decrementBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('-1'); + }); + + it('should reset counter on button click', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + incrementBtn.click(); + incrementBtn.click(); + + const resetBtn = document.querySelector('[data-counter-action="reset"]'); + resetBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('0'); + }); + + it('should save counter value to localStorage on click', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + incrementBtn.click(); + + expect(localStorage.getItem('ys_counter_value')).toBe('2'); + }); + + it('should add updated class on click for visual feedback', () => { + jest.useFakeTimers(); + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.classList.contains('updated')).toBe(true); + + jest.advanceTimersByTime(300); + expect(value.classList.contains('updated')).toBe(false); + jest.useRealTimers(); + }); + + it('should handle multiple counter blocks', () => { + document.body.innerHTML = ` +
+ 0 + +
+
+ 0 + +
+ `; + Drupal.behaviors.ysDemo.initCounterBlock(document); + + const blocks = document.querySelectorAll('[data-the-force-demo-counter]'); + expect(blocks[0].classList.contains('the-force-demo-counter-processed')).toBe( + true, + ); + expect(blocks[1].classList.contains('the-force-demo-counter-processed')).toBe( + true, + ); + }); + }); + + describe('attach', () => { + it('should call initCounterBlock with the context', () => { + document.body.innerHTML = createCounterBlockHtml(); + const spy = jest.spyOn(Drupal.behaviors.ysDemo, 'initCounterBlock'); + + Drupal.behaviors.ysDemo.attach(document); + + expect(spy).toHaveBeenCalledWith(document); + spy.mockRestore(); + }); + + it('should fully initialize when called as a behavior', () => { + document.body.innerHTML = createCounterBlockHtml(); + Drupal.behaviors.ysDemo.attach(document); + + const incrementBtn = document.querySelector( + '[data-counter-action="increment"]', + ); + incrementBtn.click(); + + const value = document.querySelector('[data-counter-value]'); + expect(value.textContent).toBe('1'); + expect(localStorage.getItem('ys_counter_value')).toBe('1'); + }); + }); +}); diff --git a/.vortex/installer/tests/Fixtures/handler_process/provision_profile/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/provision_profile/.github/workflows/build-test-deploy.yml index e734f63c1..64a248e90 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/provision_profile/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/provision_profile/.github/workflows/build-test-deploy.yml @@ -175,7 +175,7 @@ - name: Login to container registry run: ./scripts/vortex/login-container-registry.sh -@@ -495,7 +355,6 @@ +@@ -501,7 +361,6 @@ deploy: runs-on: ubuntu-latest needs: [build, lint] diff --git a/.vortex/installer/tests/Fixtures/handler_process/timezone_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/timezone_circleci/.circleci/config.yml index d6fa3a565..16659c5c8 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/timezone_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/timezone_circleci/.circleci/config.yml @@ -325,6 +325,7 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \ if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" - run: name: Provision site @@ -336,6 +337,10 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh no_output_timeout: 30m + - run: + name: Test with Jest + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + - run: name: Test with PHPUnit command: | diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_lint_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_lint_circleci/.circleci/config.yml index 61e18627c..9bbfb5413 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_lint_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_lint_circleci/.circleci/config.yml @@ -309,6 +309,7 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \ if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" - run: name: Provision site @@ -320,6 +321,10 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh no_output_timeout: 30m + - run: + name: Test with Jest + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + - run: name: Test with PHPUnit command: | diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests/.ahoy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests/.ahoy.yml index 1b83b43e5..a3a7ea510 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests/.ahoy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests/.ahoy.yml @@ -18,11 +18,10 @@ lint-fix: usage: Fix lint issues of back-end and front-end code. cmd: | -@@ -218,32 +212,6 @@ - ahoy cli vendor/bin/twig-cs-fixer lint --fix +@@ -219,34 +213,9 @@ ahoy cli "yarn run lint-fix" ahoy cli "yarn run --cwd=\${WEBROOT}/themes/custom/\${DRUPAL_THEME} lint-fix" -- + - test: - usage: Run all PHPUnit tests. - cmd: ahoy cli vendor/bin/phpunit "$@" @@ -40,9 +39,12 @@ - cmd: ahoy cli vendor/bin/phpunit --testsuite=functional "$@" - - test-functional-javascript: -- aliases: [test-js] - usage: Run PHPUnit functional JavaScript tests. - cmd: ahoy cli vendor/bin/phpunit --testsuite=functional-javascript "$@" +- + test-js: + usage: Run Jest JavaScript unit tests. + cmd: ahoy cli "yarn test" - - test-bdd: - usage: Run BDD tests. diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests/.github/workflows/build-test-deploy.yml index 45fba9470..57b4caa63 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests/.github/workflows/build-test-deploy.yml @@ -9,11 +9,10 @@ - name: Lint module code with NodeJS linters run: docker compose exec -T cli bash -c "yarn run lint" continue-on-error: ${{ vars.VORTEX_CI_NODEJS_LINT_IGNORE_FAILURE == '1' }} -@@ -374,88 +370,6 @@ - docker compose cp -L .data/db.sql cli:/app/.data/db.sql - fi - docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh -- timeout-minutes: 30 +@@ -381,88 +377,6 @@ + if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} + run: docker compose exec -T cli bash -c "yarn test" + continue-on-error: ${{ vars.VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE == '1' }} - - - name: Test with PHPUnit - if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} @@ -95,6 +94,7 @@ - env: - VORTEX_CI_BEHAT_PROFILE: ${{ vars.VORTEX_CI_BEHAT_PROFILE }} - continue-on-error: ${{ vars.VORTEX_CI_BEHAT_IGNORE_FAILURE == '1' }} - timeout-minutes: 30 +- timeout-minutes: 30 - name: Process test logs and artifacts + if: always() diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests/AGENTS.md b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests/AGENTS.md index 4a1a607fa..39a88b8ea 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests/AGENTS.md +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests/AGENTS.md @@ -1,4 +1,4 @@ -@@ -52,16 +52,6 @@ +@@ -52,19 +52,9 @@ ahoy lint # Check code style ahoy lint-fix # Auto-fix code style @@ -9,6 +9,9 @@ -ahoy test-functional # Run PHPUnit Functional tests -ahoy test -- --filter=TestClassName # Run specific PHPUnit test class - + # Jest testing + ahoy test-js # Run Jest JavaScript unit tests + -# Behat testing -ahoy test-bdd # Run Behat tests -ahoy test-bdd -- --tags=@tagname # Run Behat tests with specific tag diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests_circleci/.ahoy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests_circleci/.ahoy.yml index 1b83b43e5..a3a7ea510 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests_circleci/.ahoy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests_circleci/.ahoy.yml @@ -18,11 +18,10 @@ lint-fix: usage: Fix lint issues of back-end and front-end code. cmd: | -@@ -218,32 +212,6 @@ - ahoy cli vendor/bin/twig-cs-fixer lint --fix +@@ -219,34 +213,9 @@ ahoy cli "yarn run lint-fix" ahoy cli "yarn run --cwd=\${WEBROOT}/themes/custom/\${DRUPAL_THEME} lint-fix" -- + - test: - usage: Run all PHPUnit tests. - cmd: ahoy cli vendor/bin/phpunit "$@" @@ -40,9 +39,12 @@ - cmd: ahoy cli vendor/bin/phpunit --testsuite=functional "$@" - - test-functional-javascript: -- aliases: [test-js] - usage: Run PHPUnit functional JavaScript tests. - cmd: ahoy cli vendor/bin/phpunit --testsuite=functional-javascript "$@" +- + test-js: + usage: Run Jest JavaScript unit tests. + cmd: ahoy cli "yarn test" - - test-bdd: - usage: Run BDD tests. diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests_circleci/.circleci/config.yml index dc61bdb31..84f3ef566 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests_circleci/.circleci/config.yml @@ -321,6 +321,7 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \ if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" - run: name: Provision site @@ -332,6 +333,10 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh no_output_timeout: 30m + - run: + name: Test with Jest + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + - run: name: Process test logs and artifacts command: | diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests_circleci/AGENTS.md b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests_circleci/AGENTS.md index 4a1a607fa..39a88b8ea 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests_circleci/AGENTS.md +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests_circleci/AGENTS.md @@ -1,4 +1,4 @@ -@@ -52,16 +52,6 @@ +@@ -52,19 +52,9 @@ ahoy lint # Check code style ahoy lint-fix # Auto-fix code style @@ -9,6 +9,9 @@ -ahoy test-functional # Run PHPUnit Functional tests -ahoy test -- --filter=TestClassName # Run specific PHPUnit test class - + # Jest testing + ahoy test-js # Run Jest JavaScript unit tests + -# Behat testing -ahoy test-bdd # Run Behat tests -ahoy test-bdd -- --tags=@tagname # Run Behat tests with specific tag diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/-jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/-jest.config.js new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/.ahoy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/.ahoy.yml index 77491026e..ff8f10d38 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/.ahoy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/.ahoy.yml @@ -1,12 +1,4 @@ -@@ -156,7 +156,6 @@ - fei: - usage: Install front-end assets. - cmd: | -- ahoy cli "yarn install --frozen-lockfile" - ahoy cli "yarn --cwd=${WEBROOT}/themes/custom/${DRUPAL_THEME} install --frozen-lockfile" - - fe: -@@ -192,7 +191,6 @@ +@@ -192,7 +192,6 @@ usage: Lint front-end code. cmd: | ahoy cli vendor/bin/twig-cs-fixer lint @@ -14,7 +6,7 @@ ahoy cli "yarn run --cwd=\${WEBROOT}/themes/custom/\${DRUPAL_THEME} lint" lint-tests: -@@ -216,7 +214,6 @@ +@@ -216,7 +215,6 @@ usage: Fix lint issues of front-end code. cmd: | ahoy cli vendor/bin/twig-cs-fixer lint --fix @@ -22,3 +14,14 @@ ahoy cli "yarn run --cwd=\${WEBROOT}/themes/custom/\${DRUPAL_THEME} lint-fix" test: +@@ -238,10 +236,6 @@ + test-functional-javascript: + usage: Run PHPUnit functional JavaScript tests. + cmd: ahoy cli vendor/bin/phpunit --testsuite=functional-javascript "$@" +- +- test-js: +- usage: Run Jest JavaScript unit tests. +- cmd: ahoy cli "yarn test" + + test-bdd: + usage: Run BDD tests. diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/.github/workflows/build-test-deploy.yml index abf9480cf..88fa6ad1b 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/.github/workflows/build-test-deploy.yml @@ -6,14 +6,34 @@ - name: Audit Composer packages run: docker compose exec -T cli composer audit -@@ -157,10 +156,6 @@ - - name: Lint code with Gherkin Lint +@@ -158,10 +157,6 @@ run: docker compose exec -T cli vendor/bin/gherkinlint lint tests/behat/features continue-on-error: ${{ vars.VORTEX_CI_GHERKIN_LINT_IGNORE_FAILURE == '1' }} -- + - - name: Lint module code with NodeJS linters - run: docker compose exec -T cli bash -c "yarn run lint" - continue-on-error: ${{ vars.VORTEX_CI_NODEJS_LINT_IGNORE_FAILURE == '1' }} - +- - name: Lint theme code with NodeJS linters if: ${{ vars.VORTEX_FRONTEND_BUILD_SKIP != '1' }} + run: docker compose exec -T cli bash -c "yarn --cwd=\${WEBROOT}/themes/custom/\${DRUPAL_THEME} run lint" +@@ -366,7 +361,6 @@ + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \ + if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ + COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" +- docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" + + - name: Provision site + run: | +@@ -376,11 +370,6 @@ + fi + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh + timeout-minutes: 30 +- +- - name: Test with Jest +- if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} +- run: docker compose exec -T cli bash -c "yarn test" +- continue-on-error: ${{ vars.VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE == '1' }} + + - name: Test with PHPUnit + if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/AGENTS.md b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/AGENTS.md new file mode 100644 index 000000000..3bd67d24d --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/AGENTS.md @@ -0,0 +1,10 @@ +@@ -59,9 +59,6 @@ + ahoy test-functional # Run PHPUnit Functional tests + ahoy test -- --filter=TestClassName # Run specific PHPUnit test class + +-# Jest testing +-ahoy test-js # Run Jest JavaScript unit tests +- + # Behat testing + ahoy test-bdd # Run Behat tests + ahoy test-bdd -- --tags=@tagname # Run Behat tests with specific tag diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/web/modules/custom/sw_demo/js/-sw_demo.test.js b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/web/modules/custom/sw_demo/js/-sw_demo.test.js new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_circleci/-jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_circleci/-jest.config.js new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_circleci/.ahoy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_circleci/.ahoy.yml index 77491026e..ff8f10d38 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_circleci/.ahoy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_circleci/.ahoy.yml @@ -1,12 +1,4 @@ -@@ -156,7 +156,6 @@ - fei: - usage: Install front-end assets. - cmd: | -- ahoy cli "yarn install --frozen-lockfile" - ahoy cli "yarn --cwd=${WEBROOT}/themes/custom/${DRUPAL_THEME} install --frozen-lockfile" - - fe: -@@ -192,7 +191,6 @@ +@@ -192,7 +192,6 @@ usage: Lint front-end code. cmd: | ahoy cli vendor/bin/twig-cs-fixer lint @@ -14,7 +6,7 @@ ahoy cli "yarn run --cwd=\${WEBROOT}/themes/custom/\${DRUPAL_THEME} lint" lint-tests: -@@ -216,7 +214,6 @@ +@@ -216,7 +215,6 @@ usage: Fix lint issues of front-end code. cmd: | ahoy cli vendor/bin/twig-cs-fixer lint --fix @@ -22,3 +14,14 @@ ahoy cli "yarn run --cwd=\${WEBROOT}/themes/custom/\${DRUPAL_THEME} lint-fix" test: +@@ -238,10 +236,6 @@ + test-functional-javascript: + usage: Run PHPUnit functional JavaScript tests. + cmd: ahoy cli vendor/bin/phpunit --testsuite=functional-javascript "$@" +- +- test-js: +- usage: Run Jest JavaScript unit tests. +- cmd: ahoy cli "yarn test" + + test-bdd: + usage: Run BDD tests. diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_circleci/AGENTS.md b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_circleci/AGENTS.md new file mode 100644 index 000000000..3bd67d24d --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_circleci/AGENTS.md @@ -0,0 +1,10 @@ +@@ -59,9 +59,6 @@ + ahoy test-functional # Run PHPUnit Functional tests + ahoy test -- --filter=TestClassName # Run specific PHPUnit test class + +-# Jest testing +-ahoy test-js # Run Jest JavaScript unit tests +- + # Behat testing + ahoy test-bdd # Run Behat tests + ahoy test-bdd -- --tags=@tagname # Run Behat tests with specific tag diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_circleci/web/modules/custom/sw_demo/js/-sw_demo.test.js b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_circleci/web/modules/custom/sw_demo/js/-sw_demo.test.js new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/-jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/-jest.config.js new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/.ahoy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/.ahoy.yml index 552725dd2..6b6e52b20 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/.ahoy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/.ahoy.yml @@ -52,3 +52,14 @@ test: usage: Run all PHPUnit tests. +@@ -238,10 +212,6 @@ + test-functional-javascript: + usage: Run PHPUnit functional JavaScript tests. + cmd: ahoy cli vendor/bin/phpunit --testsuite=functional-javascript "$@" +- +- test-js: +- usage: Run Jest JavaScript unit tests. +- cmd: ahoy cli "yarn test" + + test-bdd: + usage: Run BDD tests. diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/.github/workflows/build-test-deploy.yml index 7629caf10..1430c7bb8 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/.github/workflows/build-test-deploy.yml @@ -6,11 +6,10 @@ - name: Audit Composer packages run: docker compose exec -T cli composer audit -@@ -157,15 +156,6 @@ - - name: Lint code with Gherkin Lint +@@ -158,15 +157,6 @@ run: docker compose exec -T cli vendor/bin/gherkinlint lint tests/behat/features continue-on-error: ${{ vars.VORTEX_CI_GHERKIN_LINT_IGNORE_FAILURE == '1' }} -- + - - name: Lint module code with NodeJS linters - run: docker compose exec -T cli bash -c "yarn run lint" - continue-on-error: ${{ vars.VORTEX_CI_NODEJS_LINT_IGNORE_FAILURE == '1' }} @@ -19,6 +18,27 @@ - if: ${{ vars.VORTEX_FRONTEND_BUILD_SKIP != '1' }} - run: docker compose exec -T cli bash -c "yarn --cwd=\${WEBROOT}/themes/custom/\${DRUPAL_THEME} run lint" - continue-on-error: ${{ vars.VORTEX_CI_NODEJS_LINT_IGNORE_FAILURE == '1' }} - +- database: runs-on: ubuntu-latest + if: ${{ !inputs.deploy_target && (github.event_name == 'push' || !startsWith(github.head_ref, 'project/')) }} +@@ -366,7 +356,6 @@ + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \ + if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ + COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" +- docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" + + - name: Provision site + run: | +@@ -376,11 +365,6 @@ + fi + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh + timeout-minutes: 30 +- +- - name: Test with Jest +- if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} +- run: docker compose exec -T cli bash -c "yarn test" +- continue-on-error: ${{ vars.VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE == '1' }} + + - name: Test with PHPUnit + if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/AGENTS.md b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/AGENTS.md new file mode 100644 index 000000000..3bd67d24d --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/AGENTS.md @@ -0,0 +1,10 @@ +@@ -59,9 +59,6 @@ + ahoy test-functional # Run PHPUnit Functional tests + ahoy test -- --filter=TestClassName # Run specific PHPUnit test class + +-# Jest testing +-ahoy test-js # Run Jest JavaScript unit tests +- + # Behat testing + ahoy test-bdd # Run Behat tests + ahoy test-bdd -- --tags=@tagname # Run Behat tests with specific tag diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/web/modules/custom/sw_demo/js/-sw_demo.test.js b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/web/modules/custom/sw_demo/js/-sw_demo.test.js new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme_circleci/-jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme_circleci/-jest.config.js new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme_circleci/.ahoy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme_circleci/.ahoy.yml index 552725dd2..6b6e52b20 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme_circleci/.ahoy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme_circleci/.ahoy.yml @@ -52,3 +52,14 @@ test: usage: Run all PHPUnit tests. +@@ -238,10 +212,6 @@ + test-functional-javascript: + usage: Run PHPUnit functional JavaScript tests. + cmd: ahoy cli vendor/bin/phpunit --testsuite=functional-javascript "$@" +- +- test-js: +- usage: Run Jest JavaScript unit tests. +- cmd: ahoy cli "yarn test" + + test-bdd: + usage: Run BDD tests. diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme_circleci/AGENTS.md b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme_circleci/AGENTS.md new file mode 100644 index 000000000..3bd67d24d --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme_circleci/AGENTS.md @@ -0,0 +1,10 @@ +@@ -59,9 +59,6 @@ + ahoy test-functional # Run PHPUnit Functional tests + ahoy test -- --filter=TestClassName # Run specific PHPUnit test class + +-# Jest testing +-ahoy test-js # Run Jest JavaScript unit tests +- + # Behat testing + ahoy test-bdd # Run Behat tests + ahoy test-bdd -- --tags=@tagname # Run Behat tests with specific tag diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme_circleci/web/modules/custom/sw_demo/js/-sw_demo.test.js b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme_circleci/web/modules/custom/sw_demo/js/-sw_demo.test.js new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat/.ahoy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat/.ahoy.yml index 95a936442..eef81b19f 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat/.ahoy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat/.ahoy.yml @@ -15,10 +15,10 @@ lint-fix: usage: Fix lint issues of back-end and front-end code. cmd: | -@@ -239,11 +236,6 @@ - aliases: [test-js] - usage: Run PHPUnit functional JavaScript tests. - cmd: ahoy cli vendor/bin/phpunit --testsuite=functional-javascript "$@" +@@ -242,11 +239,6 @@ + test-js: + usage: Run Jest JavaScript unit tests. + cmd: ahoy cli "yarn test" - - test-bdd: - usage: Run BDD tests. diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat/.github/workflows/build-test-deploy.yml index caba2ca13..b1df6e3d3 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat/.github/workflows/build-test-deploy.yml @@ -9,7 +9,7 @@ - name: Lint module code with NodeJS linters run: docker compose exec -T cli bash -c "yarn run lint" continue-on-error: ${{ vars.VORTEX_CI_NODEJS_LINT_IGNORE_FAILURE == '1' }} -@@ -445,18 +441,6 @@ +@@ -451,18 +447,6 @@ fi env: VORTEX_CI_CODE_COVERAGE_THRESHOLD: ${{ vars.VORTEX_CI_CODE_COVERAGE_THRESHOLD || '90' }} diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat/AGENTS.md b/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat/AGENTS.md index 0006a1bc5..79ac0ed1a 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat/AGENTS.md +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat/AGENTS.md @@ -1,6 +1,6 @@ -@@ -59,9 +59,6 @@ - ahoy test-functional # Run PHPUnit Functional tests - ahoy test -- --filter=TestClassName # Run specific PHPUnit test class +@@ -62,9 +62,6 @@ + # Jest testing + ahoy test-js # Run Jest JavaScript unit tests -# Behat testing -ahoy test-bdd # Run Behat tests diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat_circleci/.ahoy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat_circleci/.ahoy.yml index 95a936442..eef81b19f 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat_circleci/.ahoy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat_circleci/.ahoy.yml @@ -15,10 +15,10 @@ lint-fix: usage: Fix lint issues of back-end and front-end code. cmd: | -@@ -239,11 +236,6 @@ - aliases: [test-js] - usage: Run PHPUnit functional JavaScript tests. - cmd: ahoy cli vendor/bin/phpunit --testsuite=functional-javascript "$@" +@@ -242,11 +239,6 @@ + test-js: + usage: Run Jest JavaScript unit tests. + cmd: ahoy cli "yarn test" - - test-bdd: - usage: Run BDD tests. diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat_circleci/.circleci/config.yml index c15652b01..5017a2f71 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat_circleci/.circleci/config.yml @@ -321,6 +321,7 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \ if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" - run: name: Provision site @@ -332,6 +333,10 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh no_output_timeout: 30m + - run: + name: Test with Jest + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + - run: name: Test with PHPUnit command: | diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat_circleci/AGENTS.md b/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat_circleci/AGENTS.md index 0006a1bc5..79ac0ed1a 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat_circleci/AGENTS.md +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat_circleci/AGENTS.md @@ -1,6 +1,6 @@ -@@ -59,9 +59,6 @@ - ahoy test-functional # Run PHPUnit Functional tests - ahoy test -- --filter=TestClassName # Run specific PHPUnit test class +@@ -62,9 +62,6 @@ + # Jest testing + ahoy test-js # Run Jest JavaScript unit tests -# Behat testing -ahoy test-bdd # Run Behat tests diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint/package.json index 752712570..718afcd48 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint/package.json @@ -1,4 +1,4 @@ -@@ -8,24 +8,12 @@ +@@ -8,27 +8,15 @@ "node": ">= __VERSION__" }, "scripts": { @@ -8,11 +8,14 @@ - "lint-fix-js": "eslint web/modules/custom --ext .js --no-error-on-unmatched-pattern --fix", + "lint": "yarn run lint-css", "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", -- "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css" -+ "lint-fix": "yarn run lint-fix-css" +- "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", ++ "lint-fix": "yarn run lint-fix-css", + "test": "jest" }, "devDependencies": { - "@homer0/prettier-plugin-jsdoc": "__VERSION__", + "jest": "__VERSION__", + "jest-environment-jsdom": "__VERSION__", - "eslint": "__VERSION__", - "eslint-config-airbnb-base": "__VERSION__", - "eslint-config-prettier": "__VERSION__", diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_circleci/.circleci/config.yml index 1d1757698..35d3702e2 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_circleci/.circleci/config.yml @@ -320,6 +320,7 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \ if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" - run: name: Provision site @@ -331,6 +332,10 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh no_output_timeout: 30m + - run: + name: Test with Jest + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + - run: name: Test with PHPUnit command: | diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_circleci/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_circleci/package.json index 752712570..718afcd48 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_circleci/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_circleci/package.json @@ -1,4 +1,4 @@ -@@ -8,24 +8,12 @@ +@@ -8,27 +8,15 @@ "node": ">= __VERSION__" }, "scripts": { @@ -8,11 +8,14 @@ - "lint-fix-js": "eslint web/modules/custom --ext .js --no-error-on-unmatched-pattern --fix", + "lint": "yarn run lint-css", "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", -- "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css" -+ "lint-fix": "yarn run lint-fix-css" +- "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", ++ "lint-fix": "yarn run lint-fix-css", + "test": "jest" }, "devDependencies": { - "@homer0/prettier-plugin-jsdoc": "__VERSION__", + "jest": "__VERSION__", + "jest-environment-jsdom": "__VERSION__", - "eslint": "__VERSION__", - "eslint-config-airbnb-base": "__VERSION__", - "eslint-config-prettier": "__VERSION__", diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_no_theme/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_no_theme/package.json index 752712570..718afcd48 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_no_theme/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_no_theme/package.json @@ -1,4 +1,4 @@ -@@ -8,24 +8,12 @@ +@@ -8,27 +8,15 @@ "node": ">= __VERSION__" }, "scripts": { @@ -8,11 +8,14 @@ - "lint-fix-js": "eslint web/modules/custom --ext .js --no-error-on-unmatched-pattern --fix", + "lint": "yarn run lint-css", "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", -- "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css" -+ "lint-fix": "yarn run lint-fix-css" +- "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", ++ "lint-fix": "yarn run lint-fix-css", + "test": "jest" }, "devDependencies": { - "@homer0/prettier-plugin-jsdoc": "__VERSION__", + "jest": "__VERSION__", + "jest-environment-jsdom": "__VERSION__", - "eslint": "__VERSION__", - "eslint-config-airbnb-base": "__VERSION__", - "eslint-config-prettier": "__VERSION__", diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/-jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/-jest.config.js new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/.ahoy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/.ahoy.yml new file mode 100644 index 000000000..f31e3bcab --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/.ahoy.yml @@ -0,0 +1,11 @@ +@@ -239,10 +239,6 @@ + usage: Run PHPUnit functional JavaScript tests. + cmd: ahoy cli vendor/bin/phpunit --testsuite=functional-javascript "$@" + +- test-js: +- usage: Run Jest JavaScript unit tests. +- cmd: ahoy cli "yarn test" +- + test-bdd: + usage: Run BDD tests. + aliases: [test-behat] diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/.github/workflows/build-test-deploy.yml new file mode 100644 index 000000000..8a85d8e7f --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/.github/workflows/build-test-deploy.yml @@ -0,0 +1,20 @@ +@@ -366,7 +366,6 @@ + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \ + if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ + COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" +- docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" + + - name: Provision site + run: | +@@ -376,11 +375,6 @@ + fi + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh + timeout-minutes: 30 +- +- - name: Test with Jest +- if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} +- run: docker compose exec -T cli bash -c "yarn test" +- continue-on-error: ${{ vars.VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE == '1' }} + + - name: Test with PHPUnit + if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/AGENTS.md b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/AGENTS.md new file mode 100644 index 000000000..3bd67d24d --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/AGENTS.md @@ -0,0 +1,10 @@ +@@ -59,9 +59,6 @@ + ahoy test-functional # Run PHPUnit Functional tests + ahoy test -- --filter=TestClassName # Run specific PHPUnit test class + +-# Jest testing +-ahoy test-js # Run Jest JavaScript unit tests +- + # Behat testing + ahoy test-bdd # Run Behat tests + ahoy test-bdd -- --tags=@tagname # Run Behat tests with specific tag diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/package.json new file mode 100644 index 000000000..cc07aebbd --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/package.json @@ -0,0 +1,15 @@ +@@ -13,13 +13,10 @@ + "lint": "yarn run lint-js && yarn run lint-css", + "lint-fix-js": "eslint web/modules/custom --ext .js --no-error-on-unmatched-pattern --fix", + "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", +- "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", +- "test": "jest" ++ "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css" + }, + "devDependencies": { + "@homer0/prettier-plugin-jsdoc": "__VERSION__", +- "jest": "__VERSION__", +- "jest-environment-jsdom": "__VERSION__", + "eslint": "__VERSION__", + "eslint-config-airbnb-base": "__VERSION__", + "eslint-config-prettier": "__VERSION__", diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/web/modules/custom/sw_demo/js/-sw_demo.test.js b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/web/modules/custom/sw_demo/js/-sw_demo.test.js new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/-jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/-jest.config.js new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/.ahoy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/.ahoy.yml new file mode 100644 index 000000000..f31e3bcab --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/.ahoy.yml @@ -0,0 +1,11 @@ +@@ -239,10 +239,6 @@ + usage: Run PHPUnit functional JavaScript tests. + cmd: ahoy cli vendor/bin/phpunit --testsuite=functional-javascript "$@" + +- test-js: +- usage: Run Jest JavaScript unit tests. +- cmd: ahoy cli "yarn test" +- + test-bdd: + usage: Run BDD tests. + aliases: [test-behat] diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/.circleci/config.yml new file mode 100644 index 000000000..d6fa3a565 --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/.circleci/config.yml @@ -0,0 +1,542 @@ +# CircleCI configuration file for building, testing, and deploying. +# +# This configuration file uses the "docker" executor to run the Docker stack. +# +# A "runner" container, created from a specified container image, is used to +# checkout source code and run commands defined in this file. Application Docker +# containers defined in `docker-compose.yml` run on a *remote* Docker server +# controlled by CircleCI. +# The "runner" container uses Docker client to control the remote Docker server. +version: '2.1' + +aliases: + # SSH key fingerprint to download the database. + # Replace this key fingerprint with your own and remove this comment. + - &db_ssh_fingerprint "SHA256:6d+U5QubT0eAWz+4N2wt+WM2qx6o4cvyvQ6xILETJ84" + + # SSH key fingerprint to deploy code. + # Replace this key fingerprint with your own and remove this comment. + - &deploy_ssh_fingerprint "SHA256:6d+U5QubT0eAWz+4N2wt+WM2qx6o4cvyvQ6xILETJ84" + + # Schedule to run nightly database build (to cache the database for the next day). + - &nightly_db_schedule "0 18 * * *" + + # Shared runner container configuration applied to each job. + - &runner_config + working_directory: &working_directory ~/project + environment: + VORTEX_DOWNLOAD_DB_SSH_FINGERPRINT: *db_ssh_fingerprint + VORTEX_DEPLOY_SSH_FINGERPRINT: *deploy_ssh_fingerprint + docker: + # Using the 'runner' container where each job will be executed. + # This container has all the necessary tools to run a dockerized environment. + # https://github.com/drevops/ci-runner + # https://hub.docker.com/repository/docker/drevops/ci-runner/tags + - image: drevops/ci-runner:__VERSION__ + auth: + username: ${VORTEX_CONTAINER_REGISTRY_USER} + password: ${VORTEX_CONTAINER_REGISTRY_PASS} + environment: + # Set runner timezone via UI to ensure that executed operations use correct timestamps. + # https://en.wikipedia.org/wiki/List_of_tz_database_time_zones + TZ: UTC + # Set runner terminal capabilities. + TERM: xterm-256color + # Disable strict host key checking for SSH connections. + VORTEX_SSH_DISABLE_STRICT_HOST_KEY_CHECKING: "1" + # Remove all SSH keys from the runner container. + VORTEX_SSH_REMOVE_ALL_KEYS: "1" + # How often to refresh the cache of the DB dump. Refer to `date` command. + VORTEX_CI_DB_CACHE_TIMESTAMP: +%Y%m%d + # Use previous database caches on this branch as a fallback if the above cache + # does not match (for example, the cache is available only from the previous + # day). If "no" is set, the cache will be rebuilt from scratch. + VORTEX_CI_DB_CACHE_FALLBACK: "yes" + # Which branch to use as a source of DB caches. + VORTEX_CI_DB_CACHE_BRANCH: "develop" + # Directory to store test results. + VORTEX_CI_TEST_RESULTS: &test_results /tmp/tests + # Directory to store test artifacts. + VORTEX_CI_ARTIFACTS: &artifacts /tmp/artifacts + # Directory to use for artifact deployments. + VORTEX_DEPLOY_ARTIFACT_SRC: /tmp/workspace/code + # Source code location for artifact deployments. + VORTEX_DEPLOY_ARTIFACT_ROOT: *working_directory + # Report file location for artifact deployments. + VORTEX_DEPLOY_ARTIFACT_LOG: /tmp/artifacts/deployment_log.txt + # Check only minimal stack requirements. + VORTEX_DOCTOR_CHECK_MINIMAL: 1 + # CI runner resource class. + # https://circleci.com/docs/2.0/configuration-reference/#resource_class + # Change to 'large' for faster builds. + resource_class: medium + + - &step_setup_remote_docker + setup_remote_docker: + # Docker Layer Caching allows to significantly speed up builds by caching + # images built during previous runs. + # https://circleci.com/docs/2.0/docker-layer-caching/ + docker_layer_caching: false + version: default + + - &step_process_codebase_for_ci + run: + name: Process codebase to run in CI + command: | + find . -name "docker-compose.yml" -print0 | xargs -0 -I {} sh -c "sed -i -e ''/###/d'' {} && sed -i -e ''s/##//'' {}" + mkdir -p /tmp/workspace/code + + - &load_variables_from_dotenv + run: + name: Load environment variables from .env file + # Load variables from .env file, respecting existing values, and make them available for the next steps. + command: t=$(mktemp) && export -p >"${t}" && set -a && . ./.env && set +a && . "${t}" && export -p >> "$BASH_ENV" + +################################################################################ +# JOBS +################################################################################ + +jobs: + + # Lint job runs in parallel with database and build jobs. + lint: + <<: *runner_config + steps: + - checkout + - *step_process_codebase_for_ci + - *load_variables_from_dotenv + + - run: + name: Validate Composer configuration + command: composer validate --strict || [ "${VORTEX_CI_COMPOSER_VALIDATE_IGNORE_FAILURE:-0}" -eq 1 ] + + - *step_setup_remote_docker + + - run: + name: Login to container registry + command: ./scripts/vortex/login-container-registry.sh + + - run: + name: Lint Dockerfiles with Hadolint + command: | + for file in $(find .docker -name 'Dockerfile' -o -name '*.dockerfile'); do + echo "Linting ${file}" && cat "${file}" | docker run --rm -i hadolint/hadolint || [ "${VORTEX_CI_HADOLINT_IGNORE_FAILURE:-0}" -eq 1 ] + done + + - run: + name: Lint Docker Compose files with DCLint + command: docker run --rm -v "${PWD}":/app zavoloklom/dclint:__VERSION__ . || [ "${VORTEX_CI_DCLINT_IGNORE_FAILURE:-0}" -eq 1 ] + + - run: + name: Build stack + command: docker compose up --no-deps --detach cli + + - run: + name: Install development dependencies + command: | + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \ + if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ + COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" + + - run: + name: Audit Composer packages + command: docker compose exec -T cli composer audit || [ "${VORTEX_CI_COMPOSER_AUDIT_IGNORE_FAILURE:-0}" -eq 1 ] + + - run: + name: Validate Composer configuration is normalized + command: docker compose exec -T cli composer normalize --dry-run || [ "${VORTEX_CI_COMPOSER_NORMALIZE_IGNORE_FAILURE:-0}" -eq 1 ] + + - run: + name: Lint code with PHPCS + command: docker compose exec -T cli vendor/bin/phpcs || [ "${VORTEX_CI_PHPCS_IGNORE_FAILURE:-0}" -eq 1 ] + + - run: + name: Lint code with PHPStan + command: docker compose exec -T cli vendor/bin/phpstan || [ "${VORTEX_CI_PHPSTAN_IGNORE_FAILURE:-0}" -eq 1 ] + + - run: + name: Lint code with Rector + command: docker compose exec -T cli vendor/bin/rector --dry-run || [ "${VORTEX_CI_RECTOR_IGNORE_FAILURE:-0}" -eq 1 ] + + - run: + name: Lint code with PHPMD + command: docker compose exec -T cli vendor/bin/phpmd . text phpmd.xml || [ "${VORTEX_CI_PHPMD_IGNORE_FAILURE:-0}" -eq 1 ] + + - run: + name: Lint code with Twig CS Fixer + command: docker compose exec -T cli vendor/bin/twig-cs-fixer || [ "${VORTEX_CI_TWIG_CS_FIXER_IGNORE_FAILURE:-0}" -eq 1 ] + + - run: + name: Lint code with Gherkin Lint + command: docker compose exec -T cli vendor/bin/gherkinlint lint tests/behat/features || [ "${VORTEX_CI_GHERKIN_LINT_IGNORE_FAILURE:-0}" -eq 1 ] + + - run: + name: Lint module code with NodeJS linters + command: docker compose exec -T cli bash -c "yarn run lint" || [ "${VORTEX_CI_NODEJS_LINT_IGNORE_FAILURE:-0}" -eq 1 ] + + - run: + name: Lint theme code with NodeJS linters + command: | + [ "${VORTEX_FRONTEND_BUILD_SKIP:-0}" -eq 1 ] && exit 0 + docker compose exec -T cli bash -c "yarn --cwd=\${WEBROOT}/themes/custom/\${DRUPAL_THEME} run lint" || [ "${VORTEX_CI_NODEJS_LINT_IGNORE_FAILURE:-0}" -eq 1 ] + + # Database handling is a first step of the build. + # - $VORTEX_CI_DB_CACHE_TIMESTAMP is used to determine if a fresh DB dump + # should be downloaded for the current build. Usually, a daily database dump + # is sufficient for development activities. + # - $VORTEX_CI_DB_CACHE_FALLBACK is used if the cache did not match $VORTEX_CI_DB_CACHE_TIMESTAMP. + # This allows to rely on the cache from the previous days within the same branch. + database: &job-database + <<: *runner_config + steps: + - attach_workspace: + at: /tmp/workspace + + - add_ssh_keys: + fingerprints: + - *db_ssh_fingerprint + + - checkout + - *step_process_codebase_for_ci + - *load_variables_from_dotenv + - *step_setup_remote_docker + + - run: + name: Create cache keys for database caching as files + command: | + echo "${VORTEX_CI_DB_CACHE_BRANCH}" | tee /tmp/db_cache_branch + echo "${VORTEX_CI_DB_CACHE_FALLBACK/no/${CIRCLE_BUILD_NUM}}" | tee /tmp/db_cache_fallback + date "${VORTEX_CI_DB_CACHE_TIMESTAMP}" | tee /tmp/db_cache_timestamp + echo "yes" | tee /tmp/db_cache_fallback_yes + + - restore_cache: + keys: + # Restore DB cache based on the cache strategy set by the cache keys below. + # https://circleci.com/docs/2.0/caching/#restoring-cache + # Change 'v1' to 'v2', 'v3' etc., commit and push to force cache reset. + # Lookup cache based on the default branch and a timestamp. Allows + # to use cache from the very first build on the day (sanitized database dump, for example). + - __VERSION__{{ checksum "/tmp/db_cache_branch" }}-{{ checksum "/tmp/db_cache_fallback" }}-{{ checksum "/tmp/db_cache_timestamp" }} + # Fallback to caching by default branch name only. Allows to use + # cache from the branch build on the previous day. + - __VERSION__{{ checksum "/tmp/db_cache_branch" }}-{{ checksum "/tmp/db_cache_fallback" }}- + + - run: + name: Download DB + command: VORTEX_DOWNLOAD_DB_SEMAPHORE=/tmp/download-db-success ./scripts/vortex/download-db.sh + no_output_timeout: 30m + + # Execute commands after database download script finished: if the + # DB dump was downloaded - build the site (to ensure that the DB dump + # is valid) and export the DB using selected method (to support + # "file-to-image" or "image-to-file" conversions). + # Note that configuration changes and the DB updates are not applied, so + # the database will be cached in the same state as downloaded. + - run: + name: Export DB after download + command: | + [ ! -f /tmp/download-db-success ] && echo "==> Database download semaphore file is missing. DB export will not proceed." && exit 0 + ./scripts/vortex/login-container-registry.sh + docker compose up --detach && sleep 15 + docker compose exec cli mkdir -p .data && docker compose cp -L .data/db.sql cli:/app/.data/db.sql || true + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "VORTEX_PROVISION_POST_OPERATIONS_SKIP=1 ./scripts/vortex/provision.sh" + grep -q ^VORTEX_DB_IMAGE .env && rm .data/db.sql || true + ./scripts/vortex/export-db.sh db.sql + no_output_timeout: 30m + + - save_cache: + # Save cache per default branch and the timestamp. + # The cache will not be saved if it already exists. + # Note that the cache fallback flag is enabled for this case in order + # to save cache even if the fallback is not used when restoring it. + key: __VERSION__{{ checksum "/tmp/db_cache_branch" }}-{{ checksum "/tmp/db_cache_fallback_yes" }}-{{ checksum "/tmp/db_cache_timestamp" }} + paths: + - /root/project/.data + + # Nightly database job. Same as above, but with additional variables set. + # Triggered by the "nightly-db" schedule configured in CircleCI UI. + database-nightly: + <<: *job-database + environment: + VORTEX_DOWNLOAD_DB_SSH_FINGERPRINT: *db_ssh_fingerprint + VORTEX_DEPLOY_SSH_FINGERPRINT: *deploy_ssh_fingerprint + # Enforce fresh DB build (do not rely on fallback caches). + VORTEX_CI_DB_CACHE_FALLBACK: 'no' + # Always use fresh base image for the database (if database-in-image storage is used). + VORTEX_DB_IMAGE_BASE: drevops/mariadb-drupal-data:__VERSION__ + # Deploy container image (if database-in-image storage is used). + VORTEX_EXPORT_DB_CONTAINER_REGISTRY_DEPLOY_PROCEED: 1 + # Do not build the Drupal front-end. + VORTEX_FRONTEND_BUILD_SKIP: 1 + + # Build and test is a second step of the build. The testing is performed + # within the same job to save time on provisioning during the job. + build: &job_build + <<: *runner_config + parallelism: 2 + steps: + - attach_workspace: + at: /tmp/workspace + + - checkout + - *step_process_codebase_for_ci + - *load_variables_from_dotenv + + - run: + name: Validate Composer configuration + command: composer validate --strict || [ "${VORTEX_CI_COMPOSER_VALIDATE_IGNORE_FAILURE:-0}" -eq 1 ] + + - run: + name: Set cache keys for database caching + command: | + echo "${VORTEX_CI_DB_CACHE_BRANCH}" | tee /tmp/db_cache_branch + echo "yes" | tee /tmp/db_cache_fallback_yes + echo "$(date ${VORTEX_CI_DB_CACHE_TIMESTAMP})" | tee /tmp/db_cache_timestamp + + - restore_cache: + keys: + # Use cached artifacts from previous builds of this branch. + # https://circleci.com/docs/2.0/caching/#restoring-cache + - __VERSION__{{ checksum "/tmp/db_cache_branch" }}-{{ checksum "/tmp/db_cache_fallback_yes" }}-{{ checksum "/tmp/db_cache_timestamp" }} + - __VERSION__{{ checksum "/tmp/db_cache_branch" }}-{{ checksum "/tmp/db_cache_fallback_yes" }}- + + - *step_setup_remote_docker + + - run: + name: Login to container registry + command: ./scripts/vortex/login-container-registry.sh + + - run: + name: Build stack + command: docker compose up --detach && docker builder prune --all --force + + - run: + name: Export built codebase + command: | + echo "${VORTEX_DEPLOY_TYPES:-}" | grep -vq "artifact" && exit 0 || true + mkdir -p "/tmp/workspace/code" + docker compose cp -L cli:"/app/." "/tmp/workspace/code" + du -sh "/tmp/workspace/code" + + - run: + name: Install development dependencies + command: | + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \ + if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ + COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" + + - run: + name: Provision site + command: | + if [ -f .data/db.sql ]; then + docker compose exec cli mkdir -p .data + docker compose cp -L .data/db.sql cli:/app/.data/db.sql + fi + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh + no_output_timeout: 30m + + - run: + name: Test with PHPUnit + command: | + [ "${CIRCLE_NODE_TOTAL:-1}" -gt 1 ] && [ "${CIRCLE_NODE_INDEX:-0}" -ne 0 ] && exit 0 + docker compose exec -T cli vendor/bin/phpunit || [ "${VORTEX_CI_PHPUNIT_IGNORE_FAILURE:-0}" -eq 1 ] + + - run: + name: Process PHPUnit logs and coverage + command: | + [ "${CIRCLE_NODE_TOTAL:-1}" -gt 1 ] && [ "${CIRCLE_NODE_INDEX:-0}" -ne 0 ] && exit 0 + mkdir -p "${VORTEX_CI_ARTIFACTS}" + if docker compose ps --services --filter "status=running" | grep -q cli && docker compose exec cli test -d /app/.logs; then + docker compose cp cli:/app/.logs/. "${VORTEX_CI_ARTIFACTS}/" + fi + + - run: + name: Extract code coverage + command: | + [ "${CIRCLE_NODE_TOTAL:-1}" -gt 1 ] && [ "${CIRCLE_NODE_INDEX:-0}" -ne 0 ] && exit 0 + RATE=$(grep -om1 'line-rate="[0-9.]*"' /tmp/artifacts/coverage/phpunit/cobertura.xml | tr -cd '0-9.') + PERCENT=$(awk "BEGIN {printf \"%.2f\", $RATE*100}") + echo "Coverage: $PERCENT% (threshold: ${VORTEX_CI_CODE_COVERAGE_THRESHOLD:-90}%)" + echo "export COVERAGE_PERCENT=${PERCENT}" >> "${BASH_ENV}" + + - run: + name: Post coverage summary as PR comment + command: | + [ "${CIRCLE_NODE_TOTAL:-1}" -gt 1 ] && [ "${CIRCLE_NODE_INDEX:-0}" -ne 0 ] && exit 0 + [ "${VORTEX_CI_CODE_COVERAGE_PR_COMMENT_SKIP:-0}" = "1" ] && exit 0 + .circleci/post-coverage-comment.sh /tmp/artifacts/coverage/phpunit/coverage.txt + + - run: + name: Upload code coverage reports to Codecov + command: | + [ "${CIRCLE_NODE_TOTAL:-1}" -gt 1 ] && [ "${CIRCLE_NODE_INDEX:-0}" -ne 0 ] && exit 0 + if [ -n "${CODECOV_TOKEN}" ] && [ -d /tmp/artifacts/coverage ] && ! echo "${CIRCLE_BRANCH}" | grep -q '^deps/'; then + codecov -Z -s /tmp/artifacts/coverage; + fi + + - run: + name: Check code coverage threshold + command: | + [ "${CIRCLE_NODE_TOTAL:-1}" -gt 1 ] && [ "${CIRCLE_NODE_INDEX:-0}" -ne 0 ] && exit 0 + if [ "${COVERAGE_PERCENT//.}" -lt "$((${VORTEX_CI_CODE_COVERAGE_THRESHOLD:-90}*100))" ]; then + echo "FAIL: coverage ${COVERAGE_PERCENT}% is below threshold ${VORTEX_CI_CODE_COVERAGE_THRESHOLD:-90}%" + exit 1 + fi + + - run: + name: Test with Behat + command: | + if [ "${CIRCLE_NODE_TOTAL:-1}" -gt 1 ]; then export VORTEX_CI_BEHAT_PROFILE="${VORTEX_CI_BEHAT_PROFILE:-p${CIRCLE_NODE_INDEX}}"; fi + echo "Running with ${VORTEX_CI_BEHAT_PROFILE:-default} profile" + docker compose exec -T cli php -d memory_limit=-1 vendor/bin/behat --colors --strict --profile="${VORTEX_CI_BEHAT_PROFILE:-default}" || \ + docker compose exec -T cli php -d memory_limit=-1 vendor/bin/behat --colors --strict --rerun --profile="${VORTEX_CI_BEHAT_PROFILE:-default}" || \ + [ "${VORTEX_CI_BEHAT_IGNORE_FAILURE:-0}" -eq 1 ] + no_output_timeout: 30m + + - run: + name: Process test logs and artifacts + command: | + mkdir -p "${VORTEX_CI_TEST_RESULTS}" "${VORTEX_CI_ARTIFACTS}" + if docker compose ps --services --filter "status=running" | grep -q cli && docker compose exec cli test -d /app/.logs; then + docker compose cp cli:/app/.logs/. "${VORTEX_CI_ARTIFACTS}/" + if docker compose exec -T cli sh -c '[ -d /app/.logs/test_results/ ]'; then + docker compose cp cli:/app/.logs/test_results/. "${VORTEX_CI_TEST_RESULTS}/" + fi + fi + when: always + + - store_test_results: + path: *test_results + + - store_artifacts: + path: *artifacts + + - persist_to_workspace: + root: /tmp/workspace + paths: + - code + + # Deploy primary branches. + deploy: &job_deploy + <<: *runner_config + steps: + - attach_workspace: + at: /tmp/workspace + + - add_ssh_keys: + fingerprints: + - *deploy_ssh_fingerprint + + - checkout + - *step_process_codebase_for_ci + - *load_variables_from_dotenv + + - run: + name: Check if deployment should be skipped + command: | + if [ "${CIRCLE_PULL_REQUEST}" != "" ] && echo "${CIRCLE_BRANCH}" | grep -q "^project/"; then + echo "Skipping deployment - PR from project/* branch" + circleci-agent step halt + fi + + - run: + name: Deploy + command: | + VORTEX_DEPLOY_BRANCH="${CIRCLE_BRANCH}" \ + VORTEX_DEPLOY_PR="$(echo ${CIRCLE_PULL_REQUEST} | cut -d'/' -f 7)" \ + VORTEX_DEPLOY_PR_HEAD=${CIRCLE_SHA1} \ + ./scripts/vortex/deploy.sh + no_output_timeout: 30m + + - store_artifacts: + path: *artifacts + + # Deploy tags. + deploy-tags: &job-deploy-tags + <<: *runner_config + steps: + - attach_workspace: + at: /tmp/workspace + + - add_ssh_keys: + fingerprints: + - *deploy_ssh_fingerprint + + - checkout + - *step_process_codebase_for_ci + - *load_variables_from_dotenv + + - run: + name: Deploy + command: VORTEX_DEPLOY_MODE="tag" ./scripts/vortex/deploy.sh + no_output_timeout: 30m + + - store_artifacts: + path: *artifacts + +################################################################################ +# WORKFLOWS +################################################################################ + +workflows: + # Commit workflow. Runs for every commit push to the remote repository. + commit: + jobs: + - database: + filters: + tags: + only: /.*/ + - lint: + filters: + tags: + only: /.*/ + - build: + requires: + - database + filters: + tags: + only: /.*/ + - deploy: + requires: + - build + - lint + filters: + branches: + # Allowed branches: + # - production, main, master, develop, ci, cisomething + # - project/description + # - deps/* + # - feature/description, feature/123-description + # - bugfix/description, bugfix/123-description + # - release/__VERSION__, release/__VERSION__ (per https://semver.org/) + # - release/2023-04-17, release/2023-04-17.123 (date-based) + # - hotfix/__VERSION__, hotfix/__VERSION__ (per https://semver.org/) + # - hotfix/2023-04-17, hotfix/2023-04-17.123 (date-based) + only: /^(production|main|master|develop)$|^project\/[a-zA-z0-9\-\.]+|^(feature|bugfix)\/[a-zA-Z0-9\-\.\,_]+$|^ci.*|^(release|hotfix)\/[0-9]+(\.[0-9]+){2}(-rc\.[0-9]+)?$|^(release|hotfix)\/[0-9]{4}-[0-9]{2}-[0-9]{2}(\.[0-9]+)?$/ + tags: + ignore: /.*/ + - deploy-tags: + requires: + - build + - lint + filters: + branches: + ignore: /.*/ + tags: + # Allowed tags: + # - __VERSION__, __VERSION__ (per https://semver.org/) + # - 2023-04-17, 2023-04-17.123 (date-based) + only: /^[0-9]+(\.[0-9]+){2}(-rc\.[0-9]+)?$|^[0-9]{4}-[0-9]{2}-[0-9]{2}(\.[0-9]+)?$/ + + # Nightly database workflow runs overnight to capture fresh database and cache it. + nightly-db: + triggers: + - schedule: + cron: *nightly_db_schedule + filters: + branches: + only: + - develop + jobs: + - database-nightly diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/.circleci/post-coverage-comment.sh b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/.circleci/post-coverage-comment.sh new file mode 100755 index 000000000..d9e737409 --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/.circleci/post-coverage-comment.sh @@ -0,0 +1,79 @@ +#!/usr/bin/env bash +## +## Post code coverage summary as a PR comment on GitHub. +## +## Minimizes previous coverage comments before posting a new one. +## +## Environment variables: +## CIRCLE_PULL_REQUEST - CircleCI PR URL. +## GITHUB_TOKEN - GitHub token for API access. +## CIRCLE_PROJECT_USERNAME - GitHub org/user. +## CIRCLE_PROJECT_REPONAME - GitHub repo name. +## VORTEX_CI_CODE_COVERAGE_THRESHOLD - Coverage threshold percentage (default: 90). +## +## Usage: +## .circleci/post-coverage-comment.sh /path/to/coverage.txt + +set -euo pipefail + +COVERAGE_FILE="${1:-}" + +if [ -z "${COVERAGE_FILE}" ] || [ ! -f "${COVERAGE_FILE}" ]; then + echo "ERROR: Coverage file not found: ${COVERAGE_FILE}" >&2 + exit 1 +fi + +if [ -z "${CIRCLE_PULL_REQUEST:-}" ]; then + echo "Not a pull request. Skipping." + exit 0 +fi + +if [ -z "${GITHUB_TOKEN:-}" ]; then + echo "GITHUB_TOKEN is not set. Skipping." + exit 0 +fi + +COVERAGE_SUMMARY=$(awk '/^ *Summary:/{f=1;next} f && /^$/{exit} f' "${COVERAGE_FILE}") +COVERAGE_DETAILS=$(awk 'BEGIN{s=0} /^ *Summary:/{s=1} s==1 && /^$/{s=2;next} s==2' "${COVERAGE_FILE}") +PR_NUMBER=$(echo "${CIRCLE_PULL_REQUEST}" | cut -d'/' -f 7) +REPO_SLUG="${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}" +THRESHOLD="${VORTEX_CI_CODE_COVERAGE_THRESHOLD:-90}" + +MARKER="" + +BODY=$(jq -n --arg body "**Code coverage** (threshold: ${THRESHOLD}%) +\`\`\` +${COVERAGE_SUMMARY} +\`\`\` +
+Per-class coverage + +\`\`\` +${COVERAGE_DETAILS} +\`\`\` +
+${MARKER}" '{body: $body}') + +# Minimize previous coverage comments. +COMMENTS_JSON=$(curl -s \ + -H "Authorization: token ${GITHUB_TOKEN}" \ + -H "Accept: application/vnd.github.v3+json" \ + "https://api.github.com/repos/${REPO_SLUG}/issues/${PR_NUMBER}/comments?per_page=100") + +EXISTING_IDS=$(echo "${COMMENTS_JSON}" | jq -r '.[] | select(.body | contains("")) | .node_id') + +for NODE_ID in ${EXISTING_IDS}; do + GRAPHQL_BODY=$(jq -n --arg id "${NODE_ID}" '{query: "mutation($id:ID!){minimizeComment(input:{subjectId:$id,classifier:OUTDATED}){minimizedComment{isMinimized}}}", variables: {id: $id}}') + curl -s -X POST \ + -H "Authorization: bearer ${GITHUB_TOKEN}" \ + -H "Content-Type: application/json" \ + "https://api.github.com/graphql" \ + -d "${GRAPHQL_BODY}" +done + +# Post new coverage comment. +curl -s -X POST \ + -H "Authorization: token ${GITHUB_TOKEN}" \ + -H "Accept: application/vnd.github.v3+json" \ + "https://api.github.com/repos/${REPO_SLUG}/issues/${PR_NUMBER}/comments" \ + -d "${BODY}" diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/.github/workflows/-build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/.github/workflows/-build-test-deploy.yml new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/AGENTS.md b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/AGENTS.md new file mode 100644 index 000000000..3bd67d24d --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/AGENTS.md @@ -0,0 +1,10 @@ +@@ -59,9 +59,6 @@ + ahoy test-functional # Run PHPUnit Functional tests + ahoy test -- --filter=TestClassName # Run specific PHPUnit test class + +-# Jest testing +-ahoy test-js # Run Jest JavaScript unit tests +- + # Behat testing + ahoy test-bdd # Run Behat tests + ahoy test-bdd -- --tags=@tagname # Run Behat tests with specific tag diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/README.md b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/README.md new file mode 100644 index 000000000..7738f8316 --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/README.md @@ -0,0 +1,9 @@ +@@ -9,7 +9,7 @@ + + Drupal 11 implementation of star wars for star wars Org + +-[![Database, Build, Test and Deploy](https://github.com/star_wars_org/star_wars/actions/workflows/build-test-deploy.yml/badge.svg)](https://github.com/star_wars_org/star_wars/actions/workflows/build-test-deploy.yml) ++[![CircleCI](https://circleci.com/gh/star_wars_org/star_wars.svg?style=shield)](https://circleci.com/gh/star_wars_org/star_wars) + + ![Drupal 11](https://img.shields.io/badge/Drupal-11-blue.svg) + [![codecov](https://codecov.io/gh/star_wars_org/star_wars/graph/badge.svg)](https://codecov.io/gh/star_wars_org/star_wars) diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/docs/ci.md b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/docs/ci.md new file mode 100644 index 000000000..542f58060 --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/docs/ci.md @@ -0,0 +1,12 @@ +@@ -5,9 +5,9 @@ + + ## CI provider + +-This project uses [GitHub Actions](https://github.com/features/actions). ++This project uses [CircleCI](https://circleci.com/). + +-See [GitHub Actions documentation](https://www.vortextemplate.com/docs/continuous-integration/github-actions) ++See [CircleCI documentation](https://www.vortextemplate.com/docs/continuous-integration/circleci) + for setup and configuration details. + + ## Project-specific configuration diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/package.json new file mode 100644 index 000000000..cc07aebbd --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/package.json @@ -0,0 +1,15 @@ +@@ -13,13 +13,10 @@ + "lint": "yarn run lint-js && yarn run lint-css", + "lint-fix-js": "eslint web/modules/custom --ext .js --no-error-on-unmatched-pattern --fix", + "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", +- "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", +- "test": "jest" ++ "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css" + }, + "devDependencies": { + "@homer0/prettier-plugin-jsdoc": "__VERSION__", +- "jest": "__VERSION__", +- "jest-environment-jsdom": "__VERSION__", + "eslint": "__VERSION__", + "eslint-config-airbnb-base": "__VERSION__", + "eslint-config-prettier": "__VERSION__", diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/tests/phpunit/CircleCiConfigTest.php b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/tests/phpunit/CircleCiConfigTest.php new file mode 100644 index 000000000..416620280 --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/tests/phpunit/CircleCiConfigTest.php @@ -0,0 +1,257 @@ +config = Yaml::decode($file); + } + + /** + * Tests for deploy branch regex. + * + * @see https://semver.org/ + */ + #[DataProvider('dataProviderDeployBranchRegex')] + public function testDeployBranchRegex(string $branch, bool $expected = TRUE): void { + $this->assertEquals($expected, preg_match($this->config['workflows']['commit']['jobs'][3]['deploy']['filters']['branches']['only'], $branch)); + } + + /** + * Data provider for testDeployBranchRegex(). + */ + public static function dataProviderDeployBranchRegex(): \Iterator { + // Positive branches. + yield ['production']; + yield ['main']; + yield ['master']; + yield ['develop']; + + yield ['ci']; + yield ['cisomething']; + + yield ['release/__VERSION__']; + yield ['release/__VERSION__']; + yield ['hotfix/__VERSION__']; + yield ['hotfix/__VERSION__']; + + yield ['release/2023-04-17']; + yield ['release/2023-04-17.1']; + yield ['hotfix/2023-04-17']; + yield ['hotfix/2023-04-17.1']; + + yield ['feature/description']; + yield ['feature/Description']; + yield ['feature/Description-With-Hyphens']; + yield ['feature/Description-With_Underscores']; + yield ['feature/123-description']; + yield ['feature/123-Description']; + yield ['feature/UNDERSCORES_UNDERSCORES']; + yield ['feature/123-Description-With_UNDERSCORES']; + yield ['feature/1.x']; + yield ['feature/0.x']; + yield ['feature/0.1.x']; + yield ['feature/__VERSION__.x']; + yield ['feature/1.x-description']; + yield ['feature/0.x-description']; + yield ['feature/0.1.x-description']; + yield ['feature/__VERSION__.x-description']; + + yield ['bugfix/description']; + yield ['bugfix/Description']; + yield ['bugfix/Description-With-Hyphens']; + yield ['bugfix/Description-With_Underscores']; + yield ['bugfix/123-description']; + yield ['bugfix/123-Description']; + yield ['bugfix/UNDERSCORES_UNDERSCORES']; + yield ['bugfix/123-Description-With_UNDERSCORES']; + yield ['bugfix/1.x']; + yield ['bugfix/0.x']; + yield ['bugfix/0.1.x']; + yield ['bugfix/__VERSION__.x']; + yield ['bugfix/1.x-description']; + yield ['bugfix/0.x-description']; + yield ['bugfix/0.1.x-description']; + yield ['bugfix/__VERSION__.x-description']; + + yield ['project/description']; + yield ['project/Description']; + yield ['project/Description-With-Hyphens']; + yield ['project/123-description']; + yield ['project/123-Description']; + yield ['project/1.x']; + yield ['project/0.x']; + yield ['project/0.1.x']; + yield ['project/__VERSION__.x']; + yield ['project/1.x-description']; + yield ['project/0.x-description']; + yield ['project/0.1.x-description']; + yield ['project/__VERSION__.x-description']; + + // Negative branches. + yield ['something', FALSE]; + yield ['premain', FALSE]; + yield ['premaster', FALSE]; + yield ['predevelop', FALSE]; + yield ['mainpost', FALSE]; + yield ['masterpost', FALSE]; + yield ['developpost', FALSE]; + yield ['premainpost', FALSE]; + yield ['premasterpost', FALSE]; + yield ['predeveloppost', FALSE]; + + yield ['preci', FALSE]; + yield ['precipost', FALSE]; + + yield ['deps/something', FALSE]; + yield ['deps', FALSE]; + yield ['predeps', FALSE]; + yield ['depspost', FALSE]; + yield ['predepspost', FALSE]; + + yield ['feature', FALSE]; + yield ['release', FALSE]; + yield ['hotfix', FALSE]; + yield ['prefeature', FALSE]; + yield ['prerelease', FALSE]; + yield ['prehotfix', FALSE]; + yield ['featurepost', FALSE]; + yield ['releasepost', FALSE]; + yield ['hotfixpost', FALSE]; + yield ['prefeaturepost', FALSE]; + yield ['prereleasepost', FALSE]; + yield ['prehotfixpost', FALSE]; + + yield ['release/123', FALSE]; + yield ['release/123.456', FALSE]; + yield ['hotfix/123', FALSE]; + yield ['hotfix/123.456', FALSE]; + + yield ['release/202-04-17', FALSE]; + yield ['release/2023-4-17', FALSE]; + yield ['release/2023-04-1', FALSE]; + yield ['release/pre2023-04-17', FALSE]; + yield ['release/2023-04-17post', FALSE]; + yield ['release/pre2023-04-17post', FALSE]; + + yield ['hotfix/202-04-17', FALSE]; + yield ['hotfix/2023-4-17', FALSE]; + yield ['hotfix/2023-04-1', FALSE]; + yield ['hotfix/pre2023-04-17', FALSE]; + yield ['hotfix/2023-04-17post', FALSE]; + yield ['hotfix/pre2023-04-17post', FALSE]; + + yield ['release/__VERSION__', FALSE]; + yield ['release/__VERSION__', FALSE]; + yield ['release/__VERSION__', FALSE]; + yield ['release/__VERSION__', FALSE]; + yield ['release/__VERSION__', FALSE]; + yield ['release/__VERSION__', FALSE]; + yield ['release/__VERSION__', FALSE]; + yield ['release/__VERSION__', FALSE]; + yield ['release/__VERSION__', FALSE]; + yield ['release/__VERSION__', FALSE]; + + yield ['hotfix/__VERSION__', FALSE]; + yield ['hotfix/__VERSION__', FALSE]; + yield ['hotfix/__VERSION__', FALSE]; + yield ['hotfix/__VERSION__', FALSE]; + yield ['hotfix/__VERSION__', FALSE]; + yield ['hotfix/__VERSION__', FALSE]; + yield ['hotfix/__VERSION__', FALSE]; + yield ['hotfix/__VERSION__', FALSE]; + yield ['hotfix/__VERSION__', FALSE]; + yield ['hotfix/__VERSION__', FALSE]; + + yield ['prefeature/something', FALSE]; + yield ['prefbugfix/something', FALSE]; + yield ['prerelease/something', FALSE]; + yield ['prehotfix/something', FALSE]; + yield ['featurepost/something', FALSE]; + yield ['bugfixpost/something', FALSE]; + yield ['releasepost/something', FALSE]; + yield ['hotfixpost/something', FALSE]; + yield ['prefeaturepost/something', FALSE]; + yield ['prebugfixpost/something', FALSE]; + yield ['prereleasepost/something', FALSE]; + yield ['prehotfixpost/something', FALSE]; + yield ['preproject/something', FALSE]; + yield ['projectpost/something', FALSE]; + } + + /** + * Tests for deploy tag regex. + * + * @see https://semver.org/ + */ + #[DataProvider('dataProviderDeployTagRegex')] + public function testDeployTagRegex(string $branch, bool $expected = TRUE): void { + $this->assertEquals($expected, preg_match($this->config['workflows']['commit']['jobs'][4]['deploy-tags']['filters']['tags']['only'], $branch)); + } + + /** + * Data provider for testDeployTagRegex(). + */ + public static function dataProviderDeployTagRegex(): \Iterator { + // Positive tags. + yield ['__VERSION__']; + yield ['__VERSION__']; + yield ['2023-04-17']; + yield ['2023-04-17.123']; + + // Negative tags. + yield ['123', FALSE]; + yield ['123.456', FALSE]; + yield ['__VERSION__', FALSE]; + yield ['__VERSION__', FALSE]; + yield ['__VERSION__', FALSE]; + yield ['__VERSION__', FALSE]; + yield ['__VERSION__', FALSE]; + + yield ['202-04-17', FALSE]; + yield ['2023-0-17', FALSE]; + yield ['2023-04-1', FALSE]; + yield ['pre2023-04-17', FALSE]; + yield ['2023-04-17post', FALSE]; + yield ['pre2023-04-17post', FALSE]; + yield ['2023-04-17.123.', FALSE]; + yield ['2023-04-17.pre123', FALSE]; + yield ['2023-04-17.pre123post', FALSE]; + yield ['2023-04-17.123post', FALSE]; + } + +} diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/tests/phpunit/Drupal/EnvironmentSettingsTest.php b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/tests/phpunit/Drupal/EnvironmentSettingsTest.php new file mode 100644 index 000000000..aa1deaed6 --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/tests/phpunit/Drupal/EnvironmentSettingsTest.php @@ -0,0 +1,12 @@ +@@ -280,9 +280,9 @@ + } + + /** +- * Test per-environment settings for GitHub Actions. ++ * Test per-environment settings for CircleCI. + */ +- public function testEnvironmentGha(): void { ++ public function testEnvironmentCircleCi(): void { + $this->setEnvVars([ + 'CI' => TRUE, + ]); diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/web/modules/custom/sw_demo/js/-sw_demo.test.js b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/web/modules/custom/sw_demo/js/-sw_demo.test.js new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/web/sites/default/includes/providers/-settings.gha.php b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/web/sites/default/includes/providers/-settings.gha.php new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/web/sites/default/includes/providers/settings.circleci.php b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/web/sites/default/includes/providers/settings.circleci.php new file mode 100644 index 000000000..7cad35cf8 --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/web/sites/default/includes/providers/settings.circleci.php @@ -0,0 +1,17 @@ + Date: Wed, 25 Mar 2026 09:57:04 +1100 Subject: [PATCH 06/36] [#2394] Fixed Jest config for CI: explicit jsdom environment and core exclusion. --- jest.config.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jest.config.js b/jest.config.js index b7a265ec8..45fe64114 100644 --- a/jest.config.js +++ b/jest.config.js @@ -19,8 +19,8 @@ dirs.forEach((dir) => { }); module.exports = { - testEnvironment: 'jsdom', - roots, + testEnvironment: 'jest-environment-jsdom', + roots: roots.length > 0 ? roots : ['web/modules/custom'], testMatch: ['**/*.test.js'], - testPathIgnorePatterns: ['/node_modules/', '/vendor/'], + testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/web/core/'], }; From 5d2f1968016080b6574b6dd70713f4b8c3397ed5 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 09:57:22 +1100 Subject: [PATCH 07/36] Updated snapshots. --- .../Fixtures/handler_process/_baseline/jest.config.js | 6 +++--- .../handler_process/hosting_acquia/jest.config.js | 10 ++++++++++ .../hosting_project_name___acquia/jest.config.js | 10 ++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js index b7a265ec8..45fe64114 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js @@ -19,8 +19,8 @@ dirs.forEach((dir) => { }); module.exports = { - testEnvironment: 'jsdom', - roots, + testEnvironment: 'jest-environment-jsdom', + roots: roots.length > 0 ? roots : ['web/modules/custom'], testMatch: ['**/*.test.js'], - testPathIgnorePatterns: ['/node_modules/', '/vendor/'], + testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/web/core/'], }; diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js index 5b5f2913d..197ae6560 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js @@ -7,3 +7,13 @@ const roots = []; dirs.forEach((dir) => { +@@ -20,7 +20,7 @@ + + module.exports = { + testEnvironment: 'jest-environment-jsdom', +- roots: roots.length > 0 ? roots : ['web/modules/custom'], ++ roots: roots.length > 0 ? roots : ['docroot/modules/custom'], + testMatch: ['**/*.test.js'], +- testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/web/core/'], ++ testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/docroot/core/'], + }; diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js index 5b5f2913d..197ae6560 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js @@ -7,3 +7,13 @@ const roots = []; dirs.forEach((dir) => { +@@ -20,7 +20,7 @@ + + module.exports = { + testEnvironment: 'jest-environment-jsdom', +- roots: roots.length > 0 ? roots : ['web/modules/custom'], ++ roots: roots.length > 0 ? roots : ['docroot/modules/custom'], + testMatch: ['**/*.test.js'], +- testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/web/core/'], ++ testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/docroot/core/'], + }; From da3180c1e4359ddf4dc3c121b9f2fc601d9860c2 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 10:12:42 +1100 Subject: [PATCH 08/36] [#2394] Fixed jsdom docblock and core exclusion pattern for CI. --- jest.config.js | 2 +- web/modules/custom/ys_demo/js/ys_demo.test.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/jest.config.js b/jest.config.js index 45fe64114..2d7c5f4c7 100644 --- a/jest.config.js +++ b/jest.config.js @@ -22,5 +22,5 @@ module.exports = { testEnvironment: 'jest-environment-jsdom', roots: roots.length > 0 ? roots : ['web/modules/custom'], testMatch: ['**/*.test.js'], - testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/web/core/'], + testPathIgnorePatterns: ['/node_modules/', '/vendor/', 'web/core/'], }; diff --git a/web/modules/custom/ys_demo/js/ys_demo.test.js b/web/modules/custom/ys_demo/js/ys_demo.test.js index 3b51d2539..03c8f24d5 100644 --- a/web/modules/custom/ys_demo/js/ys_demo.test.js +++ b/web/modules/custom/ys_demo/js/ys_demo.test.js @@ -1,3 +1,7 @@ +/** + * @jest-environment jsdom + */ + const fs = require('fs'); const path = require('path'); From 36c71ba6fdf51b88c356509fbd57260d1ca1c1ea Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 10:12:53 +1100 Subject: [PATCH 09/36] Updated snapshots. --- .../tests/Fixtures/handler_process/_baseline/jest.config.js | 2 +- .../_baseline/web/modules/custom/sw_demo/js/sw_demo.test.js | 4 ++++ .../docroot/modules/custom/sw_demo/js/sw_demo.test.js | 4 ++++ .../Fixtures/handler_process/hosting_acquia/jest.config.js | 4 ++-- .../docroot/modules/custom/sw_demo/js/sw_demo.test.js | 4 ++++ .../hosting_project_name___acquia/jest.config.js | 4 ++-- .../modules/custom/the_force_demo/js/the_force_demo.test.js | 4 ++++ 7 files changed, 21 insertions(+), 5 deletions(-) diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js index 45fe64114..2d7c5f4c7 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js @@ -22,5 +22,5 @@ module.exports = { testEnvironment: 'jest-environment-jsdom', roots: roots.length > 0 ? roots : ['web/modules/custom'], testMatch: ['**/*.test.js'], - testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/web/core/'], + testPathIgnorePatterns: ['/node_modules/', '/vendor/', 'web/core/'], }; diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/web/modules/custom/sw_demo/js/sw_demo.test.js b/.vortex/installer/tests/Fixtures/handler_process/_baseline/web/modules/custom/sw_demo/js/sw_demo.test.js index 244df74d2..a423fda42 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/web/modules/custom/sw_demo/js/sw_demo.test.js +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/web/modules/custom/sw_demo/js/sw_demo.test.js @@ -1,3 +1,7 @@ +/** + * @jest-environment jsdom + */ + const fs = require('fs'); const path = require('path'); diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/docroot/modules/custom/sw_demo/js/sw_demo.test.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/docroot/modules/custom/sw_demo/js/sw_demo.test.js index 244df74d2..a423fda42 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/docroot/modules/custom/sw_demo/js/sw_demo.test.js +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/docroot/modules/custom/sw_demo/js/sw_demo.test.js @@ -1,3 +1,7 @@ +/** + * @jest-environment jsdom + */ + const fs = require('fs'); const path = require('path'); diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js index 197ae6560..c2a80ef73 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js @@ -14,6 +14,6 @@ - roots: roots.length > 0 ? roots : ['web/modules/custom'], + roots: roots.length > 0 ? roots : ['docroot/modules/custom'], testMatch: ['**/*.test.js'], -- testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/web/core/'], -+ testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/docroot/core/'], +- testPathIgnorePatterns: ['/node_modules/', '/vendor/', 'web/core/'], ++ testPathIgnorePatterns: ['/node_modules/', '/vendor/', 'docroot/core/'], }; diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/docroot/modules/custom/sw_demo/js/sw_demo.test.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/docroot/modules/custom/sw_demo/js/sw_demo.test.js index 244df74d2..a423fda42 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/docroot/modules/custom/sw_demo/js/sw_demo.test.js +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/docroot/modules/custom/sw_demo/js/sw_demo.test.js @@ -1,3 +1,7 @@ +/** + * @jest-environment jsdom + */ + const fs = require('fs'); const path = require('path'); diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js index 197ae6560..c2a80ef73 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js @@ -14,6 +14,6 @@ - roots: roots.length > 0 ? roots : ['web/modules/custom'], + roots: roots.length > 0 ? roots : ['docroot/modules/custom'], testMatch: ['**/*.test.js'], -- testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/web/core/'], -+ testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/docroot/core/'], +- testPathIgnorePatterns: ['/node_modules/', '/vendor/', 'web/core/'], ++ testPathIgnorePatterns: ['/node_modules/', '/vendor/', 'docroot/core/'], }; diff --git a/.vortex/installer/tests/Fixtures/handler_process/names/web/modules/custom/the_force_demo/js/the_force_demo.test.js b/.vortex/installer/tests/Fixtures/handler_process/names/web/modules/custom/the_force_demo/js/the_force_demo.test.js index 5ecf29f9c..5f3df0f6a 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/names/web/modules/custom/the_force_demo/js/the_force_demo.test.js +++ b/.vortex/installer/tests/Fixtures/handler_process/names/web/modules/custom/the_force_demo/js/the_force_demo.test.js @@ -1,3 +1,7 @@ +/** + * @jest-environment jsdom + */ + const fs = require('fs'); const path = require('path'); From 898734791a46645d002a059f9799f5298bf5b70b Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 10:27:13 +1100 Subject: [PATCH 10/36] [#2394] Added modulePathIgnorePatterns to exclude Drupal core from Jest. --- jest.config.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jest.config.js b/jest.config.js index 2d7c5f4c7..740012287 100644 --- a/jest.config.js +++ b/jest.config.js @@ -22,5 +22,6 @@ module.exports = { testEnvironment: 'jest-environment-jsdom', roots: roots.length > 0 ? roots : ['web/modules/custom'], testMatch: ['**/*.test.js'], - testPathIgnorePatterns: ['/node_modules/', '/vendor/', 'web/core/'], + testPathIgnorePatterns: ['/node_modules/', '/vendor/'], + modulePathIgnorePatterns: ['web/core/', 'web/modules/contrib/', 'web/themes/contrib/'], }; From 10ae3091b23627a87ab64eebdcc57904102f98c5 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 10:27:34 +1100 Subject: [PATCH 11/36] Updated snapshots. --- .../Fixtures/handler_process/_baseline/jest.config.js | 3 ++- .../Fixtures/handler_process/hosting_acquia/jest.config.js | 7 ++++--- .../hosting_project_name___acquia/jest.config.js | 7 ++++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js index 2d7c5f4c7..740012287 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js @@ -22,5 +22,6 @@ module.exports = { testEnvironment: 'jest-environment-jsdom', roots: roots.length > 0 ? roots : ['web/modules/custom'], testMatch: ['**/*.test.js'], - testPathIgnorePatterns: ['/node_modules/', '/vendor/', 'web/core/'], + testPathIgnorePatterns: ['/node_modules/', '/vendor/'], + modulePathIgnorePatterns: ['web/core/', 'web/modules/contrib/', 'web/themes/contrib/'], }; diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js index c2a80ef73..3319e041d 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js @@ -7,13 +7,14 @@ const roots = []; dirs.forEach((dir) => { -@@ -20,7 +20,7 @@ +@@ -20,8 +20,8 @@ module.exports = { testEnvironment: 'jest-environment-jsdom', - roots: roots.length > 0 ? roots : ['web/modules/custom'], + roots: roots.length > 0 ? roots : ['docroot/modules/custom'], testMatch: ['**/*.test.js'], -- testPathIgnorePatterns: ['/node_modules/', '/vendor/', 'web/core/'], -+ testPathIgnorePatterns: ['/node_modules/', '/vendor/', 'docroot/core/'], + testPathIgnorePatterns: ['/node_modules/', '/vendor/'], +- modulePathIgnorePatterns: ['web/core/', 'web/modules/contrib/', 'web/themes/contrib/'], ++ modulePathIgnorePatterns: ['docroot/core/', 'docroot/modules/contrib/', 'docroot/themes/contrib/'], }; diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js index c2a80ef73..3319e041d 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js @@ -7,13 +7,14 @@ const roots = []; dirs.forEach((dir) => { -@@ -20,7 +20,7 @@ +@@ -20,8 +20,8 @@ module.exports = { testEnvironment: 'jest-environment-jsdom', - roots: roots.length > 0 ? roots : ['web/modules/custom'], + roots: roots.length > 0 ? roots : ['docroot/modules/custom'], testMatch: ['**/*.test.js'], -- testPathIgnorePatterns: ['/node_modules/', '/vendor/', 'web/core/'], -+ testPathIgnorePatterns: ['/node_modules/', '/vendor/', 'docroot/core/'], + testPathIgnorePatterns: ['/node_modules/', '/vendor/'], +- modulePathIgnorePatterns: ['web/core/', 'web/modules/contrib/', 'web/themes/contrib/'], ++ modulePathIgnorePatterns: ['docroot/core/', 'docroot/modules/contrib/', 'docroot/themes/contrib/'], }; From c9e50206de796ea7e05bee9bf845c2cba54b8bad Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 10:41:22 +1100 Subject: [PATCH 12/36] [#2394] Fixed testPathIgnorePatterns for core exclusion and ESLint jsdoc warning. --- .eslintrc.json | 3 ++- jest.config.js | 5 ++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 7208a7e8f..091de0679 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -67,7 +67,8 @@ "env": { "jest": true }, "rules": { "no-eval": "off", - "max-nested-callbacks": ["warn", 5] + "max-nested-callbacks": ["warn", 5], + "jsdoc/check-tag-names": "off" } } ], diff --git a/jest.config.js b/jest.config.js index 740012287..3b89144bd 100644 --- a/jest.config.js +++ b/jest.config.js @@ -20,8 +20,7 @@ dirs.forEach((dir) => { module.exports = { testEnvironment: 'jest-environment-jsdom', - roots: roots.length > 0 ? roots : ['web/modules/custom'], + roots: roots.length > 0 ? roots : [path.resolve('web/modules/custom')], testMatch: ['**/*.test.js'], - testPathIgnorePatterns: ['/node_modules/', '/vendor/'], - modulePathIgnorePatterns: ['web/core/', 'web/modules/contrib/', 'web/themes/contrib/'], + testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/web/core/', '/web/modules/contrib/', '/web/themes/contrib/'], }; From f0eff21681dde2c0af0d9fa6ee0a08510103bb0b Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 10:41:41 +1100 Subject: [PATCH 13/36] Updated snapshots. --- .../Fixtures/handler_process/_baseline/.eslintrc.json | 3 ++- .../Fixtures/handler_process/_baseline/jest.config.js | 5 ++--- .../handler_process/hosting_acquia/jest.config.js | 11 +++++------ .../hosting_project_name___acquia/jest.config.js | 11 +++++------ 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/.eslintrc.json b/.vortex/installer/tests/Fixtures/handler_process/_baseline/.eslintrc.json index 7208a7e8f..091de0679 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/.eslintrc.json +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/.eslintrc.json @@ -67,7 +67,8 @@ "env": { "jest": true }, "rules": { "no-eval": "off", - "max-nested-callbacks": ["warn", 5] + "max-nested-callbacks": ["warn", 5], + "jsdoc/check-tag-names": "off" } } ], diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js index 740012287..3b89144bd 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js @@ -20,8 +20,7 @@ dirs.forEach((dir) => { module.exports = { testEnvironment: 'jest-environment-jsdom', - roots: roots.length > 0 ? roots : ['web/modules/custom'], + roots: roots.length > 0 ? roots : [path.resolve('web/modules/custom')], testMatch: ['**/*.test.js'], - testPathIgnorePatterns: ['/node_modules/', '/vendor/'], - modulePathIgnorePatterns: ['web/core/', 'web/modules/contrib/', 'web/themes/contrib/'], + testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/web/core/', '/web/modules/contrib/', '/web/themes/contrib/'], }; diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js index 3319e041d..67aa2efa9 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js @@ -7,14 +7,13 @@ const roots = []; dirs.forEach((dir) => { -@@ -20,8 +20,8 @@ +@@ -20,7 +20,7 @@ module.exports = { testEnvironment: 'jest-environment-jsdom', -- roots: roots.length > 0 ? roots : ['web/modules/custom'], -+ roots: roots.length > 0 ? roots : ['docroot/modules/custom'], +- roots: roots.length > 0 ? roots : [path.resolve('web/modules/custom')], ++ roots: roots.length > 0 ? roots : [path.resolve('docroot/modules/custom')], testMatch: ['**/*.test.js'], - testPathIgnorePatterns: ['/node_modules/', '/vendor/'], -- modulePathIgnorePatterns: ['web/core/', 'web/modules/contrib/', 'web/themes/contrib/'], -+ modulePathIgnorePatterns: ['docroot/core/', 'docroot/modules/contrib/', 'docroot/themes/contrib/'], +- testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/web/core/', '/web/modules/contrib/', '/web/themes/contrib/'], ++ testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/docroot/core/', '/docroot/modules/contrib/', '/docroot/themes/contrib/'], }; diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js index 3319e041d..67aa2efa9 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js @@ -7,14 +7,13 @@ const roots = []; dirs.forEach((dir) => { -@@ -20,8 +20,8 @@ +@@ -20,7 +20,7 @@ module.exports = { testEnvironment: 'jest-environment-jsdom', -- roots: roots.length > 0 ? roots : ['web/modules/custom'], -+ roots: roots.length > 0 ? roots : ['docroot/modules/custom'], +- roots: roots.length > 0 ? roots : [path.resolve('web/modules/custom')], ++ roots: roots.length > 0 ? roots : [path.resolve('docroot/modules/custom')], testMatch: ['**/*.test.js'], - testPathIgnorePatterns: ['/node_modules/', '/vendor/'], -- modulePathIgnorePatterns: ['web/core/', 'web/modules/contrib/', 'web/themes/contrib/'], -+ modulePathIgnorePatterns: ['docroot/core/', 'docroot/modules/contrib/', 'docroot/themes/contrib/'], +- testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/web/core/', '/web/modules/contrib/', '/web/themes/contrib/'], ++ testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/docroot/core/', '/docroot/modules/contrib/', '/docroot/themes/contrib/'], }; From 1600374c651265cf5533fdb4c638395da43dd572 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 10:57:07 +1100 Subject: [PATCH 14/36] [#2394] Used explicit testMatch pattern to restrict Jest to custom modules only. --- jest.config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jest.config.js b/jest.config.js index 3b89144bd..888b96ace 100644 --- a/jest.config.js +++ b/jest.config.js @@ -21,6 +21,6 @@ dirs.forEach((dir) => { module.exports = { testEnvironment: 'jest-environment-jsdom', roots: roots.length > 0 ? roots : [path.resolve('web/modules/custom')], - testMatch: ['**/*.test.js'], - testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/web/core/', '/web/modules/contrib/', '/web/themes/contrib/'], + testMatch: ['**/web/modules/custom/*/js/**/*.test.js'], + testPathIgnorePatterns: ['/node_modules/', '/vendor/'], }; From 71ddb2ae1ed94286636874368dd9b3d39be2e54e Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 10:57:26 +1100 Subject: [PATCH 15/36] Updated snapshots. --- .../tests/Fixtures/handler_process/_baseline/jest.config.js | 4 ++-- .../Fixtures/handler_process/hosting_acquia/jest.config.js | 6 +++--- .../hosting_project_name___acquia/jest.config.js | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js index 3b89144bd..888b96ace 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js @@ -21,6 +21,6 @@ dirs.forEach((dir) => { module.exports = { testEnvironment: 'jest-environment-jsdom', roots: roots.length > 0 ? roots : [path.resolve('web/modules/custom')], - testMatch: ['**/*.test.js'], - testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/web/core/', '/web/modules/contrib/', '/web/themes/contrib/'], + testMatch: ['**/web/modules/custom/*/js/**/*.test.js'], + testPathIgnorePatterns: ['/node_modules/', '/vendor/'], }; diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js index 67aa2efa9..8a93ecef0 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js @@ -12,8 +12,8 @@ module.exports = { testEnvironment: 'jest-environment-jsdom', - roots: roots.length > 0 ? roots : [path.resolve('web/modules/custom')], +- testMatch: ['**/web/modules/custom/*/js/**/*.test.js'], + roots: roots.length > 0 ? roots : [path.resolve('docroot/modules/custom')], - testMatch: ['**/*.test.js'], -- testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/web/core/', '/web/modules/contrib/', '/web/themes/contrib/'], -+ testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/docroot/core/', '/docroot/modules/contrib/', '/docroot/themes/contrib/'], ++ testMatch: ['**/docroot/modules/custom/*/js/**/*.test.js'], + testPathIgnorePatterns: ['/node_modules/', '/vendor/'], }; diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js index 67aa2efa9..8a93ecef0 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js @@ -12,8 +12,8 @@ module.exports = { testEnvironment: 'jest-environment-jsdom', - roots: roots.length > 0 ? roots : [path.resolve('web/modules/custom')], +- testMatch: ['**/web/modules/custom/*/js/**/*.test.js'], + roots: roots.length > 0 ? roots : [path.resolve('docroot/modules/custom')], - testMatch: ['**/*.test.js'], -- testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/web/core/', '/web/modules/contrib/', '/web/themes/contrib/'], -+ testPathIgnorePatterns: ['/node_modules/', '/vendor/', '/docroot/core/', '/docroot/modules/contrib/', '/docroot/themes/contrib/'], ++ testMatch: ['**/docroot/modules/custom/*/js/**/*.test.js'], + testPathIgnorePatterns: ['/node_modules/', '/vendor/'], }; From 1f8c6d83e1f9d81e2045dbf6940f9756d25adab9 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 11:10:00 +1100 Subject: [PATCH 16/36] [#2394] Added modulePathIgnorePatterns to prevent Jest scanning Drupal core. --- jest.config.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/jest.config.js b/jest.config.js index 888b96ace..bba332a98 100644 --- a/jest.config.js +++ b/jest.config.js @@ -23,4 +23,10 @@ module.exports = { roots: roots.length > 0 ? roots : [path.resolve('web/modules/custom')], testMatch: ['**/web/modules/custom/*/js/**/*.test.js'], testPathIgnorePatterns: ['/node_modules/', '/vendor/'], + modulePathIgnorePatterns: [ + '/web/core/', + '/web/modules/contrib/', + '/web/themes/contrib/', + '/web/themes/custom/', + ], }; From 227c31d8595424ce9aafa48ec33d969da6c983d7 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 11:10:45 +1100 Subject: [PATCH 17/36] Updated snapshots. --- .../handler_process/_baseline/jest.config.js | 6 ++++++ .../handler_process/hosting_acquia/jest.config.js | 12 +++++++++++- .../hosting_project_name___acquia/jest.config.js | 12 +++++++++++- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js index 888b96ace..bba332a98 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js @@ -23,4 +23,10 @@ module.exports = { roots: roots.length > 0 ? roots : [path.resolve('web/modules/custom')], testMatch: ['**/web/modules/custom/*/js/**/*.test.js'], testPathIgnorePatterns: ['/node_modules/', '/vendor/'], + modulePathIgnorePatterns: [ + '/web/core/', + '/web/modules/contrib/', + '/web/themes/contrib/', + '/web/themes/custom/', + ], }; diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js index 8a93ecef0..d91580c76 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js @@ -7,7 +7,7 @@ const roots = []; dirs.forEach((dir) => { -@@ -20,7 +20,7 @@ +@@ -20,13 +20,13 @@ module.exports = { testEnvironment: 'jest-environment-jsdom', @@ -16,4 +16,14 @@ + roots: roots.length > 0 ? roots : [path.resolve('docroot/modules/custom')], + testMatch: ['**/docroot/modules/custom/*/js/**/*.test.js'], testPathIgnorePatterns: ['/node_modules/', '/vendor/'], + modulePathIgnorePatterns: [ +- '/web/core/', +- '/web/modules/contrib/', +- '/web/themes/contrib/', +- '/web/themes/custom/', ++ '/docroot/core/', ++ '/docroot/modules/contrib/', ++ '/docroot/themes/contrib/', ++ '/docroot/themes/custom/', + ], }; diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js index 8a93ecef0..d91580c76 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js @@ -7,7 +7,7 @@ const roots = []; dirs.forEach((dir) => { -@@ -20,7 +20,7 @@ +@@ -20,13 +20,13 @@ module.exports = { testEnvironment: 'jest-environment-jsdom', @@ -16,4 +16,14 @@ + roots: roots.length > 0 ? roots : [path.resolve('docroot/modules/custom')], + testMatch: ['**/docroot/modules/custom/*/js/**/*.test.js'], testPathIgnorePatterns: ['/node_modules/', '/vendor/'], + modulePathIgnorePatterns: [ +- '/web/core/', +- '/web/modules/contrib/', +- '/web/themes/contrib/', +- '/web/themes/custom/', ++ '/docroot/core/', ++ '/docroot/modules/contrib/', ++ '/docroot/themes/contrib/', ++ '/docroot/themes/custom/', + ], }; From d6fecee9b954edc6b7967c84742db99f50168d1b Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 11:41:37 +1100 Subject: [PATCH 18/36] [#2394] Added debug logging to jest.config.js for CI investigation. --- jest.config.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/jest.config.js b/jest.config.js index bba332a98..fc891d982 100644 --- a/jest.config.js +++ b/jest.config.js @@ -18,15 +18,13 @@ dirs.forEach((dir) => { } }); +// eslint-disable-next-line no-console +console.log('Jest roots:', JSON.stringify(roots)); + module.exports = { testEnvironment: 'jest-environment-jsdom', roots: roots.length > 0 ? roots : [path.resolve('web/modules/custom')], - testMatch: ['**/web/modules/custom/*/js/**/*.test.js'], + testMatch: ['**/*.test.js'], testPathIgnorePatterns: ['/node_modules/', '/vendor/'], - modulePathIgnorePatterns: [ - '/web/core/', - '/web/modules/contrib/', - '/web/themes/contrib/', - '/web/themes/custom/', - ], + modulePathIgnorePatterns: ['/web/core/', '/web/modules/contrib/', '/web/themes/'], }; From a88e2aae8ed4d876dcd66c0badee4f67e1b47a8d Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 11:51:33 +1100 Subject: [PATCH 19/36] [#2394] Used testRegex to strictly match only custom module test files. --- jest.config.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/jest.config.js b/jest.config.js index fc891d982..0cf2f8a1f 100644 --- a/jest.config.js +++ b/jest.config.js @@ -18,13 +18,10 @@ dirs.forEach((dir) => { } }); -// eslint-disable-next-line no-console -console.log('Jest roots:', JSON.stringify(roots)); - module.exports = { testEnvironment: 'jest-environment-jsdom', roots: roots.length > 0 ? roots : [path.resolve('web/modules/custom')], - testMatch: ['**/*.test.js'], + testRegex: 'web/modules/custom/.+\\.test\\.js$', testPathIgnorePatterns: ['/node_modules/', '/vendor/'], modulePathIgnorePatterns: ['/web/core/', '/web/modules/contrib/', '/web/themes/'], }; From 225e62f865394c10ab2b4bffb150b2895360b092 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 11:51:56 +1100 Subject: [PATCH 20/36] Updated snapshots. --- .../handler_process/_baseline/jest.config.js | 9 ++------- .../hosting_acquia/jest.config.js | 18 +++++------------- .../jest.config.js | 18 +++++------------- 3 files changed, 12 insertions(+), 33 deletions(-) diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js index bba332a98..0cf2f8a1f 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js @@ -21,12 +21,7 @@ dirs.forEach((dir) => { module.exports = { testEnvironment: 'jest-environment-jsdom', roots: roots.length > 0 ? roots : [path.resolve('web/modules/custom')], - testMatch: ['**/web/modules/custom/*/js/**/*.test.js'], + testRegex: 'web/modules/custom/.+\\.test\\.js$', testPathIgnorePatterns: ['/node_modules/', '/vendor/'], - modulePathIgnorePatterns: [ - '/web/core/', - '/web/modules/contrib/', - '/web/themes/contrib/', - '/web/themes/custom/', - ], + modulePathIgnorePatterns: ['/web/core/', '/web/modules/contrib/', '/web/themes/'], }; diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js index d91580c76..9249836ac 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js @@ -7,23 +7,15 @@ const roots = []; dirs.forEach((dir) => { -@@ -20,13 +20,13 @@ +@@ -20,8 +20,8 @@ module.exports = { testEnvironment: 'jest-environment-jsdom', - roots: roots.length > 0 ? roots : [path.resolve('web/modules/custom')], -- testMatch: ['**/web/modules/custom/*/js/**/*.test.js'], +- testRegex: 'web/modules/custom/.+\\.test\\.js$', + roots: roots.length > 0 ? roots : [path.resolve('docroot/modules/custom')], -+ testMatch: ['**/docroot/modules/custom/*/js/**/*.test.js'], ++ testRegex: 'docroot/modules/custom/.+\\.test\\.js$', testPathIgnorePatterns: ['/node_modules/', '/vendor/'], - modulePathIgnorePatterns: [ -- '/web/core/', -- '/web/modules/contrib/', -- '/web/themes/contrib/', -- '/web/themes/custom/', -+ '/docroot/core/', -+ '/docroot/modules/contrib/', -+ '/docroot/themes/contrib/', -+ '/docroot/themes/custom/', - ], +- modulePathIgnorePatterns: ['/web/core/', '/web/modules/contrib/', '/web/themes/'], ++ modulePathIgnorePatterns: ['/docroot/core/', '/docroot/modules/contrib/', '/docroot/themes/'], }; diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js index d91580c76..9249836ac 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js @@ -7,23 +7,15 @@ const roots = []; dirs.forEach((dir) => { -@@ -20,13 +20,13 @@ +@@ -20,8 +20,8 @@ module.exports = { testEnvironment: 'jest-environment-jsdom', - roots: roots.length > 0 ? roots : [path.resolve('web/modules/custom')], -- testMatch: ['**/web/modules/custom/*/js/**/*.test.js'], +- testRegex: 'web/modules/custom/.+\\.test\\.js$', + roots: roots.length > 0 ? roots : [path.resolve('docroot/modules/custom')], -+ testMatch: ['**/docroot/modules/custom/*/js/**/*.test.js'], ++ testRegex: 'docroot/modules/custom/.+\\.test\\.js$', testPathIgnorePatterns: ['/node_modules/', '/vendor/'], - modulePathIgnorePatterns: [ -- '/web/core/', -- '/web/modules/contrib/', -- '/web/themes/contrib/', -- '/web/themes/custom/', -+ '/docroot/core/', -+ '/docroot/modules/contrib/', -+ '/docroot/themes/contrib/', -+ '/docroot/themes/custom/', - ], +- modulePathIgnorePatterns: ['/web/core/', '/web/modules/contrib/', '/web/themes/'], ++ modulePathIgnorePatterns: ['/docroot/core/', '/docroot/modules/contrib/', '/docroot/themes/'], }; From 58c8d91498594e54577c04a95c6874861db796e2 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 12:06:40 +1100 Subject: [PATCH 21/36] [#2394] Added explicit --config flag to Jest command. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0fbe69c09..dc20dbf9e 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "lint-fix-js": "eslint web/modules/custom --ext .js --no-error-on-unmatched-pattern --fix", "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", - "test": "jest" + "test": "jest --config jest.config.js" }, "devDependencies": { "@homer0/prettier-plugin-jsdoc": "^11.0.1", From c0086e6616a7a4d898b47d284d6ec3b0cec68bab Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 12:06:59 +1100 Subject: [PATCH 22/36] Updated snapshots. --- .../tests/Fixtures/handler_process/_baseline/package.json | 2 +- .../tests/Fixtures/handler_process/hosting_acquia/package.json | 2 +- .../handler_process/hosting_project_name___acquia/package.json | 2 +- .../tests/Fixtures/handler_process/tools_no_eslint/package.json | 2 +- .../handler_process/tools_no_eslint_circleci/package.json | 2 +- .../handler_process/tools_no_eslint_no_theme/package.json | 2 +- .../tests/Fixtures/handler_process/tools_no_jest/package.json | 2 +- .../handler_process/tools_no_jest_circleci/package.json | 2 +- .../Fixtures/handler_process/tools_no_stylelint/package.json | 2 +- .../handler_process/tools_no_stylelint_circleci/package.json | 2 +- .../handler_process/tools_no_stylelint_no_theme/package.json | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/package.json b/.vortex/installer/tests/Fixtures/handler_process/_baseline/package.json index 62eac946c..f1e21d27b 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/package.json @@ -14,7 +14,7 @@ "lint-fix-js": "eslint web/modules/custom --ext .js --no-error-on-unmatched-pattern --fix", "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", - "test": "jest" + "test": "jest --config jest.config.js" }, "devDependencies": { "@homer0/prettier-plugin-jsdoc": "__VERSION__", diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/package.json b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/package.json index 40c40de58..7200a7e42 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/package.json @@ -12,5 +12,5 @@ + "lint-fix-js": "eslint docroot/modules/custom --ext .js --no-error-on-unmatched-pattern --fix", + "lint-fix-css": "stylelint --allow-empty-input \"docroot/modules/custom/**/*.css\" --fix", "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", - "test": "jest" + "test": "jest --config jest.config.js" }, diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/package.json b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/package.json index 40c40de58..7200a7e42 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/package.json @@ -12,5 +12,5 @@ + "lint-fix-js": "eslint docroot/modules/custom --ext .js --no-error-on-unmatched-pattern --fix", + "lint-fix-css": "stylelint --allow-empty-input \"docroot/modules/custom/**/*.css\" --fix", "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", - "test": "jest" + "test": "jest --config jest.config.js" }, diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint/package.json index 718afcd48..fecb043df 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint/package.json @@ -10,7 +10,7 @@ "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", - "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", + "lint-fix": "yarn run lint-fix-css", - "test": "jest" + "test": "jest --config jest.config.js" }, "devDependencies": { - "@homer0/prettier-plugin-jsdoc": "__VERSION__", diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_circleci/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_circleci/package.json index 718afcd48..fecb043df 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_circleci/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_circleci/package.json @@ -10,7 +10,7 @@ "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", - "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", + "lint-fix": "yarn run lint-fix-css", - "test": "jest" + "test": "jest --config jest.config.js" }, "devDependencies": { - "@homer0/prettier-plugin-jsdoc": "__VERSION__", diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_no_theme/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_no_theme/package.json index 718afcd48..fecb043df 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_no_theme/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_no_theme/package.json @@ -10,7 +10,7 @@ "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", - "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", + "lint-fix": "yarn run lint-fix-css", - "test": "jest" + "test": "jest --config jest.config.js" }, "devDependencies": { - "@homer0/prettier-plugin-jsdoc": "__VERSION__", diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/package.json index cc07aebbd..5a19723f5 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/package.json @@ -3,7 +3,7 @@ "lint-fix-js": "eslint web/modules/custom --ext .js --no-error-on-unmatched-pattern --fix", "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", - "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", -- "test": "jest" +- "test": "jest --config jest.config.js" + "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css" }, "devDependencies": { diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/package.json index cc07aebbd..5a19723f5 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/package.json @@ -3,7 +3,7 @@ "lint-fix-js": "eslint web/modules/custom --ext .js --no-error-on-unmatched-pattern --fix", "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", - "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", -- "test": "jest" +- "test": "jest --config jest.config.js" + "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css" }, "devDependencies": { diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint/package.json index 02f7d388b..47702e87a 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint/package.json @@ -9,7 +9,7 @@ - "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", - "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", + "lint-fix": "yarn run lint-fix-js", - "test": "jest" + "test": "jest --config jest.config.js" }, "devDependencies": { @@ -28,9 +26,6 @@ diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_circleci/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_circleci/package.json index 02f7d388b..47702e87a 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_circleci/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_circleci/package.json @@ -9,7 +9,7 @@ - "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", - "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", + "lint-fix": "yarn run lint-fix-js", - "test": "jest" + "test": "jest --config jest.config.js" }, "devDependencies": { @@ -28,9 +26,6 @@ diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_no_theme/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_no_theme/package.json index 02f7d388b..47702e87a 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_no_theme/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_no_theme/package.json @@ -9,7 +9,7 @@ - "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", - "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", + "lint-fix": "yarn run lint-fix-js", - "test": "jest" + "test": "jest --config jest.config.js" }, "devDependencies": { @@ -28,9 +26,6 @@ From 7eacfc684190c6873d4a13ea9d76de7a7e66afbf Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 13:59:05 +1100 Subject: [PATCH 23/36] [#2394] Moved Jest config into package.json for Docker CI compatibility. --- jest.config.js | 27 --------------------------- package.json | 8 +++++++- 2 files changed, 7 insertions(+), 28 deletions(-) delete mode 100644 jest.config.js diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index 0cf2f8a1f..000000000 --- a/jest.config.js +++ /dev/null @@ -1,27 +0,0 @@ -const fs = require('fs'); -const path = require('path'); - -// Discover js/ directories in custom modules, resolving symlinks to real -// paths. Jest resolves symlinks internally, so roots must use real paths -// for test files to be matched. -const dirs = ['web/modules/custom']; -const roots = []; - -dirs.forEach((dir) => { - if (fs.existsSync(dir)) { - fs.readdirSync(dir).forEach((name) => { - const jsDir = path.resolve(dir, name, 'js'); - if (fs.existsSync(jsDir)) { - roots.push(jsDir); - } - }); - } -}); - -module.exports = { - testEnvironment: 'jest-environment-jsdom', - roots: roots.length > 0 ? roots : [path.resolve('web/modules/custom')], - testRegex: 'web/modules/custom/.+\\.test\\.js$', - testPathIgnorePatterns: ['/node_modules/', '/vendor/'], - modulePathIgnorePatterns: ['/web/core/', '/web/modules/contrib/', '/web/themes/'], -}; diff --git a/package.json b/package.json index dc20dbf9e..e55821d86 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "lint-fix-js": "eslint web/modules/custom --ext .js --no-error-on-unmatched-pattern --fix", "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", - "test": "jest --config jest.config.js" + "test": "jest" }, "devDependencies": { "@homer0/prettier-plugin-jsdoc": "^11.0.1", @@ -32,5 +32,11 @@ "stylelint": "^16.26.1", "stylelint-config-standard": "^36.0.1", "stylelint-order": "^6.0.4" + }, + "jest": { + "testEnvironment": "jest-environment-jsdom", + "testRegex": "web/modules/custom/.+\\.test\\.js$", + "testPathIgnorePatterns": ["/node_modules/", "/vendor/"], + "modulePathIgnorePatterns": ["/web/core/", "/web/modules/contrib/", "/web/themes/", "/.vortex/"] } } From a93acde0fdedbe8d855759b75155430de556d1d9 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 13:59:26 +1100 Subject: [PATCH 24/36] Updated snapshots. --- .../handler_process/_baseline/jest.config.js | 27 ------------------- .../handler_process/_baseline/package.json | 8 +++++- .../tools_no_eslint/package.json | 2 +- .../tools_no_eslint_circleci/package.json | 2 +- .../tools_no_eslint_no_theme/package.json | 2 +- .../tools_no_jest/-jest.config.js | 0 .../tools_no_jest/package.json | 2 +- .../tools_no_jest_circleci/-jest.config.js | 0 .../tools_no_jest_circleci/package.json | 2 +- .../tools_no_stylelint/package.json | 9 ++++--- .../tools_no_stylelint_circleci/package.json | 9 ++++--- .../tools_no_stylelint_no_theme/package.json | 9 ++++--- 12 files changed, 27 insertions(+), 45 deletions(-) delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest/-jest.config.js delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/-jest.config.js diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js deleted file mode 100644 index 0cf2f8a1f..000000000 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js +++ /dev/null @@ -1,27 +0,0 @@ -const fs = require('fs'); -const path = require('path'); - -// Discover js/ directories in custom modules, resolving symlinks to real -// paths. Jest resolves symlinks internally, so roots must use real paths -// for test files to be matched. -const dirs = ['web/modules/custom']; -const roots = []; - -dirs.forEach((dir) => { - if (fs.existsSync(dir)) { - fs.readdirSync(dir).forEach((name) => { - const jsDir = path.resolve(dir, name, 'js'); - if (fs.existsSync(jsDir)) { - roots.push(jsDir); - } - }); - } -}); - -module.exports = { - testEnvironment: 'jest-environment-jsdom', - roots: roots.length > 0 ? roots : [path.resolve('web/modules/custom')], - testRegex: 'web/modules/custom/.+\\.test\\.js$', - testPathIgnorePatterns: ['/node_modules/', '/vendor/'], - modulePathIgnorePatterns: ['/web/core/', '/web/modules/contrib/', '/web/themes/'], -}; diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/package.json b/.vortex/installer/tests/Fixtures/handler_process/_baseline/package.json index f1e21d27b..11a671af3 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/package.json @@ -14,7 +14,7 @@ "lint-fix-js": "eslint web/modules/custom --ext .js --no-error-on-unmatched-pattern --fix", "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", - "test": "jest --config jest.config.js" + "test": "jest" }, "devDependencies": { "@homer0/prettier-plugin-jsdoc": "__VERSION__", @@ -32,5 +32,11 @@ "stylelint": "__VERSION__", "stylelint-config-standard": "__VERSION__", "stylelint-order": "__VERSION__" + }, + "jest": { + "testEnvironment": "jest-environment-jsdom", + "testRegex": "web/modules/custom/.+\\.test\\.js$", + "testPathIgnorePatterns": ["/node_modules/", "/vendor/"], + "modulePathIgnorePatterns": ["/web/core/", "/web/modules/contrib/", "/web/themes/", "/.vortex/"] } } diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint/package.json index fecb043df..718afcd48 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint/package.json @@ -10,7 +10,7 @@ "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", - "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", + "lint-fix": "yarn run lint-fix-css", - "test": "jest --config jest.config.js" + "test": "jest" }, "devDependencies": { - "@homer0/prettier-plugin-jsdoc": "__VERSION__", diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_circleci/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_circleci/package.json index fecb043df..718afcd48 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_circleci/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_circleci/package.json @@ -10,7 +10,7 @@ "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", - "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", + "lint-fix": "yarn run lint-fix-css", - "test": "jest --config jest.config.js" + "test": "jest" }, "devDependencies": { - "@homer0/prettier-plugin-jsdoc": "__VERSION__", diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_no_theme/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_no_theme/package.json index fecb043df..718afcd48 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_no_theme/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_no_theme/package.json @@ -10,7 +10,7 @@ "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", - "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", + "lint-fix": "yarn run lint-fix-css", - "test": "jest --config jest.config.js" + "test": "jest" }, "devDependencies": { - "@homer0/prettier-plugin-jsdoc": "__VERSION__", diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/-jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/-jest.config.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/package.json index 5a19723f5..cc07aebbd 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/package.json @@ -3,7 +3,7 @@ "lint-fix-js": "eslint web/modules/custom --ext .js --no-error-on-unmatched-pattern --fix", "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", - "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", -- "test": "jest --config jest.config.js" +- "test": "jest" + "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css" }, "devDependencies": { diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/-jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/-jest.config.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/package.json index 5a19723f5..cc07aebbd 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/package.json @@ -3,7 +3,7 @@ "lint-fix-js": "eslint web/modules/custom --ext .js --no-error-on-unmatched-pattern --fix", "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", - "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", -- "test": "jest --config jest.config.js" +- "test": "jest" + "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css" }, "devDependencies": { diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint/package.json index 47702e87a..fbcda3cff 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint/package.json @@ -9,10 +9,10 @@ - "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", - "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", + "lint-fix": "yarn run lint-fix-js", - "test": "jest --config jest.config.js" + "test": "jest" }, "devDependencies": { -@@ -28,9 +26,6 @@ +@@ -28,10 +26,7 @@ "eslint-plugin-no-jquery": "__VERSION__", "eslint-plugin-prettier": "__VERSION__", "eslint-plugin-yml": "__VERSION__", @@ -21,5 +21,6 @@ - "stylelint-config-standard": "__VERSION__", - "stylelint-order": "__VERSION__" + "prettier": "__VERSION__" - } - } + }, + "jest": { + "testEnvironment": "jest-environment-jsdom", diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_circleci/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_circleci/package.json index 47702e87a..fbcda3cff 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_circleci/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_circleci/package.json @@ -9,10 +9,10 @@ - "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", - "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", + "lint-fix": "yarn run lint-fix-js", - "test": "jest --config jest.config.js" + "test": "jest" }, "devDependencies": { -@@ -28,9 +26,6 @@ +@@ -28,10 +26,7 @@ "eslint-plugin-no-jquery": "__VERSION__", "eslint-plugin-prettier": "__VERSION__", "eslint-plugin-yml": "__VERSION__", @@ -21,5 +21,6 @@ - "stylelint-config-standard": "__VERSION__", - "stylelint-order": "__VERSION__" + "prettier": "__VERSION__" - } - } + }, + "jest": { + "testEnvironment": "jest-environment-jsdom", diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_no_theme/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_no_theme/package.json index 47702e87a..fbcda3cff 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_no_theme/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_no_theme/package.json @@ -9,10 +9,10 @@ - "lint-fix-css": "stylelint --allow-empty-input \"web/modules/custom/**/*.css\" --fix", - "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", + "lint-fix": "yarn run lint-fix-js", - "test": "jest --config jest.config.js" + "test": "jest" }, "devDependencies": { -@@ -28,9 +26,6 @@ +@@ -28,10 +26,7 @@ "eslint-plugin-no-jquery": "__VERSION__", "eslint-plugin-prettier": "__VERSION__", "eslint-plugin-yml": "__VERSION__", @@ -21,5 +21,6 @@ - "stylelint-config-standard": "__VERSION__", - "stylelint-order": "__VERSION__" + "prettier": "__VERSION__" - } - } + }, + "jest": { + "testEnvironment": "jest-environment-jsdom", From 0f7475a2f4741d80bd3109f90b957a76149a4d40 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 14:08:28 +1100 Subject: [PATCH 25/36] [#2394] Restored jest.config.js and added to .dockerignore whitelist. --- .dockerignore | 1 + jest.config.js | 32 ++++++++++++++++++++++++++++++++ package.json | 6 ------ 3 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 jest.config.js diff --git a/.dockerignore b/.dockerignore index b02049969..22f2224fb 100644 --- a/.dockerignore +++ b/.dockerignore @@ -41,6 +41,7 @@ drush/contrib/ !composer.lock !gherkinlint.json !package-lock.json +!jest.config.js !package.json !patches !phpcs.xml diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 000000000..0ac9851fc --- /dev/null +++ b/jest.config.js @@ -0,0 +1,32 @@ +const fs = require('fs'); +const path = require('path'); + +// Discover js/ directories in custom modules, resolving symlinks to real +// paths. Jest resolves symlinks internally, so roots must use real paths +// for test files to be matched. +const dirs = ['web/modules/custom']; +const roots = []; + +dirs.forEach((dir) => { + if (fs.existsSync(dir)) { + fs.readdirSync(dir).forEach((name) => { + const jsDir = path.resolve(dir, name, 'js'); + if (fs.existsSync(jsDir)) { + roots.push(jsDir); + } + }); + } +}); + +module.exports = { + testEnvironment: 'jest-environment-jsdom', + roots: roots.length > 0 ? roots : [path.resolve('web/modules/custom')], + testRegex: 'web/modules/custom/.+\\.test\\.js$', + testPathIgnorePatterns: ['/node_modules/', '/vendor/'], + modulePathIgnorePatterns: [ + '/web/core/', + '/web/modules/contrib/', + '/web/themes/', + '/.vortex/', + ], +}; diff --git a/package.json b/package.json index e55821d86..0fbe69c09 100644 --- a/package.json +++ b/package.json @@ -32,11 +32,5 @@ "stylelint": "^16.26.1", "stylelint-config-standard": "^36.0.1", "stylelint-order": "^6.0.4" - }, - "jest": { - "testEnvironment": "jest-environment-jsdom", - "testRegex": "web/modules/custom/.+\\.test\\.js$", - "testPathIgnorePatterns": ["/node_modules/", "/vendor/"], - "modulePathIgnorePatterns": ["/web/core/", "/web/modules/contrib/", "/web/themes/", "/.vortex/"] } } From 202b7a24321de3bae02c84762a292e1a4ac64fe1 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 14:08:32 +1100 Subject: [PATCH 26/36] t --- .vortex/CLAUDE.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/.vortex/CLAUDE.md b/.vortex/CLAUDE.md index bd0505caf..9e13066eb 100644 --- a/.vortex/CLAUDE.md +++ b/.vortex/CLAUDE.md @@ -88,8 +88,6 @@ When updating template scripts: **NEVER run without explicit user permission**: - `ahoy update-snapshots` -- `UPDATE_SNAPSHOTS=1 ./vendor/bin/phpunit` -- Any `UPDATE_SNAPSHOTS=1` command These modify many files and take 10-15 minutes. From 0399e351f35b4beca45f7716e93d35cb40bea3f6 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 14:08:43 +1100 Subject: [PATCH 27/36] Updated snapshots. --- .../handler_process/_baseline/.dockerignore | 1 + .../handler_process/_baseline/jest.config.js | 32 +++++++++++++++++++ .../handler_process/_baseline/package.json | 6 ---- .../hosting_acquia/.dockerignore | 2 +- .../hosting_acquia/jest.config.js | 13 ++++++-- .../hosting_acquia/package.json | 2 +- .../hosting_lagoon/.dockerignore | 2 +- .../.dockerignore | 2 +- .../jest.config.js | 13 ++++++-- .../package.json | 2 +- .../.dockerignore | 2 +- .../migration_disabled_lagoon/.dockerignore | 2 +- .../migration_enabled_lagoon/.dockerignore | 2 +- .../provision_database_lagoon/.dockerignore | 2 +- .../tools_groups_no_be_lint/.dockerignore | 4 +-- .../.dockerignore | 4 +-- .../tools_groups_no_be_tests/.dockerignore | 4 +-- .../.dockerignore | 4 +-- .../tools_no_behat/.dockerignore | 2 +- .../tools_no_behat_circleci/.dockerignore | 2 +- .../tools_no_jest/-jest.config.js | 0 .../tools_no_jest_circleci/-jest.config.js | 0 .../tools_no_phpcs/.dockerignore | 4 +-- .../tools_no_phpcs_circleci/.dockerignore | 4 +-- .../tools_no_phpmd/.dockerignore | 2 +- .../tools_no_phpmd_circleci/.dockerignore | 2 +- .../tools_no_phpstan/.dockerignore | 2 +- .../tools_no_phpstan_circleci/.dockerignore | 2 +- .../tools_no_phpunit/.dockerignore | 2 +- .../tools_no_phpunit_circleci/.dockerignore | 2 +- .../tools_no_rector/.dockerignore | 2 +- .../tools_no_rector_circleci/.dockerignore | 2 +- .../tools_no_stylelint/package.json | 7 ++-- .../tools_no_stylelint_circleci/package.json | 7 ++-- .../tools_no_stylelint_no_theme/package.json | 7 ++-- .../handler_process/tools_none/.dockerignore | 3 +- 36 files changed, 95 insertions(+), 56 deletions(-) create mode 100644 .vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest/-jest.config.js create mode 100644 .vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/-jest.config.js diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/_baseline/.dockerignore index fcbd7c174..ca2193891 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/.dockerignore @@ -40,6 +40,7 @@ drush/contrib/ !composer.lock !gherkinlint.json !package-lock.json +!jest.config.js !package.json !patches !phpcs.xml diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js new file mode 100644 index 000000000..0ac9851fc --- /dev/null +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/jest.config.js @@ -0,0 +1,32 @@ +const fs = require('fs'); +const path = require('path'); + +// Discover js/ directories in custom modules, resolving symlinks to real +// paths. Jest resolves symlinks internally, so roots must use real paths +// for test files to be matched. +const dirs = ['web/modules/custom']; +const roots = []; + +dirs.forEach((dir) => { + if (fs.existsSync(dir)) { + fs.readdirSync(dir).forEach((name) => { + const jsDir = path.resolve(dir, name, 'js'); + if (fs.existsSync(jsDir)) { + roots.push(jsDir); + } + }); + } +}); + +module.exports = { + testEnvironment: 'jest-environment-jsdom', + roots: roots.length > 0 ? roots : [path.resolve('web/modules/custom')], + testRegex: 'web/modules/custom/.+\\.test\\.js$', + testPathIgnorePatterns: ['/node_modules/', '/vendor/'], + modulePathIgnorePatterns: [ + '/web/core/', + '/web/modules/contrib/', + '/web/themes/', + '/.vortex/', + ], +}; diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/package.json b/.vortex/installer/tests/Fixtures/handler_process/_baseline/package.json index 11a671af3..62eac946c 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/package.json @@ -32,11 +32,5 @@ "stylelint": "__VERSION__", "stylelint-config-standard": "__VERSION__", "stylelint-order": "__VERSION__" - }, - "jest": { - "testEnvironment": "jest-environment-jsdom", - "testRegex": "web/modules/custom/.+\\.test\\.js$", - "testPathIgnorePatterns": ["/node_modules/", "/vendor/"], - "modulePathIgnorePatterns": ["/web/core/", "/web/modules/contrib/", "/web/themes/", "/.vortex/"] } } diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/.dockerignore index 32eb6f635..4aab2eb79 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/.dockerignore @@ -22,7 +22,7 @@ !drush drush/contrib/ -@@ -51,3 +51,5 @@ +@@ -52,3 +52,5 @@ !scripts !tests !yarn.lock diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js index 9249836ac..bf6ae3613 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/jest.config.js @@ -7,7 +7,7 @@ const roots = []; dirs.forEach((dir) => { -@@ -20,8 +20,8 @@ +@@ -20,13 +20,13 @@ module.exports = { testEnvironment: 'jest-environment-jsdom', @@ -16,6 +16,13 @@ + roots: roots.length > 0 ? roots : [path.resolve('docroot/modules/custom')], + testRegex: 'docroot/modules/custom/.+\\.test\\.js$', testPathIgnorePatterns: ['/node_modules/', '/vendor/'], -- modulePathIgnorePatterns: ['/web/core/', '/web/modules/contrib/', '/web/themes/'], -+ modulePathIgnorePatterns: ['/docroot/core/', '/docroot/modules/contrib/', '/docroot/themes/'], + modulePathIgnorePatterns: [ +- '/web/core/', +- '/web/modules/contrib/', +- '/web/themes/', ++ '/docroot/core/', ++ '/docroot/modules/contrib/', ++ '/docroot/themes/', + '/.vortex/', + ], }; diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/package.json b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/package.json index 7200a7e42..40c40de58 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_acquia/package.json @@ -12,5 +12,5 @@ + "lint-fix-js": "eslint docroot/modules/custom --ext .js --no-error-on-unmatched-pattern --fix", + "lint-fix-css": "stylelint --allow-empty-input \"docroot/modules/custom/**/*.css\" --fix", "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", - "test": "jest --config jest.config.js" + "test": "jest" }, diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_lagoon/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/hosting_lagoon/.dockerignore index 2ad15805e..eb16fbd6f 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_lagoon/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_lagoon/.dockerignore @@ -1,4 +1,4 @@ -@@ -51,3 +51,5 @@ +@@ -52,3 +52,5 @@ !scripts !tests !yarn.lock diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/.dockerignore index 32eb6f635..4aab2eb79 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/.dockerignore @@ -22,7 +22,7 @@ !drush drush/contrib/ -@@ -51,3 +51,5 @@ +@@ -52,3 +52,5 @@ !scripts !tests !yarn.lock diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js index 9249836ac..bf6ae3613 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/jest.config.js @@ -7,7 +7,7 @@ const roots = []; dirs.forEach((dir) => { -@@ -20,8 +20,8 @@ +@@ -20,13 +20,13 @@ module.exports = { testEnvironment: 'jest-environment-jsdom', @@ -16,6 +16,13 @@ + roots: roots.length > 0 ? roots : [path.resolve('docroot/modules/custom')], + testRegex: 'docroot/modules/custom/.+\\.test\\.js$', testPathIgnorePatterns: ['/node_modules/', '/vendor/'], -- modulePathIgnorePatterns: ['/web/core/', '/web/modules/contrib/', '/web/themes/'], -+ modulePathIgnorePatterns: ['/docroot/core/', '/docroot/modules/contrib/', '/docroot/themes/'], + modulePathIgnorePatterns: [ +- '/web/core/', +- '/web/modules/contrib/', +- '/web/themes/', ++ '/docroot/core/', ++ '/docroot/modules/contrib/', ++ '/docroot/themes/', + '/.vortex/', + ], }; diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/package.json b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/package.json index 7200a7e42..40c40de58 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___acquia/package.json @@ -12,5 +12,5 @@ + "lint-fix-js": "eslint docroot/modules/custom --ext .js --no-error-on-unmatched-pattern --fix", + "lint-fix-css": "stylelint --allow-empty-input \"docroot/modules/custom/**/*.css\" --fix", "lint-fix": "yarn run lint-fix-js && yarn run lint-fix-css", - "test": "jest --config jest.config.js" + "test": "jest" }, diff --git a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___lagoon/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___lagoon/.dockerignore index 2ad15805e..eb16fbd6f 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___lagoon/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/hosting_project_name___lagoon/.dockerignore @@ -1,4 +1,4 @@ -@@ -51,3 +51,5 @@ +@@ -52,3 +52,5 @@ !scripts !tests !yarn.lock diff --git a/.vortex/installer/tests/Fixtures/handler_process/migration_disabled_lagoon/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/migration_disabled_lagoon/.dockerignore index 2ad15805e..eb16fbd6f 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/migration_disabled_lagoon/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/migration_disabled_lagoon/.dockerignore @@ -1,4 +1,4 @@ -@@ -51,3 +51,5 @@ +@@ -52,3 +52,5 @@ !scripts !tests !yarn.lock diff --git a/.vortex/installer/tests/Fixtures/handler_process/migration_enabled_lagoon/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/migration_enabled_lagoon/.dockerignore index 2ad15805e..eb16fbd6f 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/migration_enabled_lagoon/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/migration_enabled_lagoon/.dockerignore @@ -1,4 +1,4 @@ -@@ -51,3 +51,5 @@ +@@ -52,3 +52,5 @@ !scripts !tests !yarn.lock diff --git a/.vortex/installer/tests/Fixtures/handler_process/provision_database_lagoon/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/provision_database_lagoon/.dockerignore index 2ad15805e..eb16fbd6f 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/provision_database_lagoon/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/provision_database_lagoon/.dockerignore @@ -1,4 +1,4 @@ -@@ -51,3 +51,5 @@ +@@ -52,3 +52,5 @@ !scripts !tests !yarn.lock diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_lint/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_lint/.dockerignore index f0f4da85f..87d269cd9 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_lint/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_lint/.dockerignore @@ -1,5 +1,5 @@ -@@ -42,12 +42,8 @@ - !package-lock.json +@@ -43,12 +43,8 @@ + !jest.config.js !package.json !patches -!phpcs.xml diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_lint_circleci/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_lint_circleci/.dockerignore index f0f4da85f..87d269cd9 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_lint_circleci/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_lint_circleci/.dockerignore @@ -1,5 +1,5 @@ -@@ -42,12 +42,8 @@ - !package-lock.json +@@ -43,12 +43,8 @@ + !jest.config.js !package.json !patches -!phpcs.xml diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests/.dockerignore index 7caffb41e..f1daa63b0 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests/.dockerignore @@ -7,9 +7,9 @@ !composer.lock -!gherkinlint.json !package-lock.json + !jest.config.js !package.json - !patches -@@ -45,7 +43,6 @@ +@@ -46,7 +44,6 @@ !phpcs.xml !phpmd.xml !phpstan.neon diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests_circleci/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests_circleci/.dockerignore index 7caffb41e..f1daa63b0 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests_circleci/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests_circleci/.dockerignore @@ -7,9 +7,9 @@ !composer.lock -!gherkinlint.json !package-lock.json + !jest.config.js !package.json - !patches -@@ -45,7 +43,6 @@ +@@ -46,7 +44,6 @@ !phpcs.xml !phpmd.xml !phpstan.neon diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat/.dockerignore index 9fcb635dc..a2fab9006 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat/.dockerignore @@ -7,5 +7,5 @@ !composer.lock -!gherkinlint.json !package-lock.json + !jest.config.js !package.json - !patches diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat_circleci/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat_circleci/.dockerignore index 9fcb635dc..a2fab9006 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat_circleci/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat_circleci/.dockerignore @@ -7,5 +7,5 @@ !composer.lock -!gherkinlint.json !package-lock.json + !jest.config.js !package.json - !patches diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/-jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/-jest.config.js new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/-jest.config.js b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest_circleci/-jest.config.js new file mode 100644 index 000000000..e69de29bb diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpcs/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpcs/.dockerignore index b84096f3e..b3fead272 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpcs/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpcs/.dockerignore @@ -1,5 +1,5 @@ -@@ -42,7 +42,6 @@ - !package-lock.json +@@ -43,7 +43,6 @@ + !jest.config.js !package.json !patches -!phpcs.xml diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpcs_circleci/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpcs_circleci/.dockerignore index b84096f3e..b3fead272 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpcs_circleci/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpcs_circleci/.dockerignore @@ -1,5 +1,5 @@ -@@ -42,7 +42,6 @@ - !package-lock.json +@@ -43,7 +43,6 @@ + !jest.config.js !package.json !patches -!phpcs.xml diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpmd/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpmd/.dockerignore index 0b2ff251c..5e9643d35 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpmd/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpmd/.dockerignore @@ -1,4 +1,4 @@ -@@ -43,7 +43,6 @@ +@@ -44,7 +44,6 @@ !package.json !patches !phpcs.xml diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpmd_circleci/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpmd_circleci/.dockerignore index 0b2ff251c..5e9643d35 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpmd_circleci/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpmd_circleci/.dockerignore @@ -1,4 +1,4 @@ -@@ -43,7 +43,6 @@ +@@ -44,7 +44,6 @@ !package.json !patches !phpcs.xml diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpstan/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpstan/.dockerignore index 7d02bae7c..f24af1018 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpstan/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpstan/.dockerignore @@ -1,4 +1,4 @@ -@@ -44,7 +44,6 @@ +@@ -45,7 +45,6 @@ !patches !phpcs.xml !phpmd.xml diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpstan_circleci/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpstan_circleci/.dockerignore index 7d02bae7c..f24af1018 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpstan_circleci/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpstan_circleci/.dockerignore @@ -1,4 +1,4 @@ -@@ -44,7 +44,6 @@ +@@ -45,7 +45,6 @@ !patches !phpcs.xml !phpmd.xml diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpunit/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpunit/.dockerignore index 0530ba723..3f219c79e 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpunit/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpunit/.dockerignore @@ -1,4 +1,4 @@ -@@ -45,7 +45,6 @@ +@@ -46,7 +46,6 @@ !phpcs.xml !phpmd.xml !phpstan.neon diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpunit_circleci/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpunit_circleci/.dockerignore index 0530ba723..3f219c79e 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpunit_circleci/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpunit_circleci/.dockerignore @@ -1,4 +1,4 @@ -@@ -45,7 +45,6 @@ +@@ -46,7 +46,6 @@ !phpcs.xml !phpmd.xml !phpstan.neon diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_rector/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/tools_no_rector/.dockerignore index 8e5664a94..9a702f8aa 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_rector/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_rector/.dockerignore @@ -1,4 +1,4 @@ -@@ -47,7 +47,6 @@ +@@ -48,7 +48,6 @@ !phpstan.neon !phpunit.xml !postcss.config.js diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_rector_circleci/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/tools_no_rector_circleci/.dockerignore index 8e5664a94..9a702f8aa 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_rector_circleci/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_rector_circleci/.dockerignore @@ -1,4 +1,4 @@ -@@ -47,7 +47,6 @@ +@@ -48,7 +48,6 @@ !phpstan.neon !phpunit.xml !postcss.config.js diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint/package.json index fbcda3cff..02f7d388b 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint/package.json @@ -12,7 +12,7 @@ "test": "jest" }, "devDependencies": { -@@ -28,10 +26,7 @@ +@@ -28,9 +26,6 @@ "eslint-plugin-no-jquery": "__VERSION__", "eslint-plugin-prettier": "__VERSION__", "eslint-plugin-yml": "__VERSION__", @@ -21,6 +21,5 @@ - "stylelint-config-standard": "__VERSION__", - "stylelint-order": "__VERSION__" + "prettier": "__VERSION__" - }, - "jest": { - "testEnvironment": "jest-environment-jsdom", + } + } diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_circleci/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_circleci/package.json index fbcda3cff..02f7d388b 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_circleci/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_circleci/package.json @@ -12,7 +12,7 @@ "test": "jest" }, "devDependencies": { -@@ -28,10 +26,7 @@ +@@ -28,9 +26,6 @@ "eslint-plugin-no-jquery": "__VERSION__", "eslint-plugin-prettier": "__VERSION__", "eslint-plugin-yml": "__VERSION__", @@ -21,6 +21,5 @@ - "stylelint-config-standard": "__VERSION__", - "stylelint-order": "__VERSION__" + "prettier": "__VERSION__" - }, - "jest": { - "testEnvironment": "jest-environment-jsdom", + } + } diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_no_theme/package.json b/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_no_theme/package.json index fbcda3cff..02f7d388b 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_no_theme/package.json +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_no_theme/package.json @@ -12,7 +12,7 @@ "test": "jest" }, "devDependencies": { -@@ -28,10 +26,7 @@ +@@ -28,9 +26,6 @@ "eslint-plugin-no-jquery": "__VERSION__", "eslint-plugin-prettier": "__VERSION__", "eslint-plugin-yml": "__VERSION__", @@ -21,6 +21,5 @@ - "stylelint-config-standard": "__VERSION__", - "stylelint-order": "__VERSION__" + "prettier": "__VERSION__" - }, - "jest": { - "testEnvironment": "jest-environment-jsdom", + } + } diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_none/.dockerignore b/.vortex/installer/tests/Fixtures/handler_process/tools_none/.dockerignore index 43140ab87..11d2c9d9a 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_none/.dockerignore +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_none/.dockerignore @@ -1,4 +1,4 @@ -@@ -35,19 +35,12 @@ +@@ -35,20 +35,13 @@ !.stylelintrc.js !.twig-cs-fixer.php !auth.json @@ -7,6 +7,7 @@ !composer.lock -!gherkinlint.json !package-lock.json + !jest.config.js !package.json !patches -!phpcs.xml From 9033e553d41b0ede74d703fa2afbde5451c28fa0 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 14:42:00 +1100 Subject: [PATCH 28/36] [#2394] Regenerated CircleCI test config. --- .circleci/vortex-test-common.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.circleci/vortex-test-common.yml b/.circleci/vortex-test-common.yml index 3a83e2063..ea6281b29 100644 --- a/.circleci/vortex-test-common.yml +++ b/.circleci/vortex-test-common.yml @@ -229,6 +229,9 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \ if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" + #;< TOOL_JEST + docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" + #;> TOOL_JEST - run: name: Provision site @@ -246,6 +249,12 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh no_output_timeout: 30m + #;< TOOL_JEST + - run: + name: Test with Jest + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + #;> TOOL_JEST + #;< TOOL_PHPUNIT - run: name: Test with PHPUnit From 26732e73ed918e3910c10a5a1434665732f693d1 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 15:05:04 +1100 Subject: [PATCH 29/36] [#2394] Added Jest documentation for tools and development sections. --- .vortex/docs/content/development/jest.mdx | 87 +++++++++++ .vortex/docs/content/tools/jest.mdx | 168 ++++++++++++++++++++++ 2 files changed, 255 insertions(+) create mode 100644 .vortex/docs/content/development/jest.mdx create mode 100644 .vortex/docs/content/tools/jest.mdx diff --git a/.vortex/docs/content/development/jest.mdx b/.vortex/docs/content/development/jest.mdx new file mode 100644 index 000000000..d910218ac --- /dev/null +++ b/.vortex/docs/content/development/jest.mdx @@ -0,0 +1,87 @@ +--- +sidebar_label: Jest +sidebar_position: 6 +--- + +# Jest + +**Vortex** uses [Jest](https://jestjs.io/) as a framework for JavaScript unit +testing. Jest tests verify that JavaScript behaviors in custom Drupal modules +work correctly in isolation, without requiring a browser or Drupal bootstrap. + +**Vortex** provides Jest support with configuration in [`jest.config.js`](https://github.com/drevops/vortex/blob/main/jest.config.js) +that automatically discovers test files in custom modules. + +## Running tests + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + ```shell + # Run all Jest tests + ahoy test-js + # Run tests matching a pattern + ahoy test-js -- --testPathPattern=ys_demo + # Run a specific test by name + ahoy test-js -- -t "should increment the value" + ``` + + + ```shell + # Run all Jest tests + docker compose exec cli bash -c "yarn test" + # Run tests matching a pattern + docker compose exec cli bash -c "yarn test --testPathPattern=ys_demo" + # Run a specific test by name + docker compose exec cli bash -c "yarn test -t 'should increment the value'" + ``` + + + +## Test file structure + +Test files are co-located with source files in the `js/` directory of each +custom module: + +```text +web/modules/custom/my_module/ +└── js/ + ├── my_module.js # Source file (Drupal behavior) + └── my_module.test.js # Jest test file +``` + +Jest automatically discovers `*.test.js` files in `web/modules/custom/*/js/` +directories. Adding a new module with tests requires no configuration changes. + +## Configuration + +The `jest.config.js` file in the project root configures: + +- Dynamic root discovery scanning `web/modules/custom/*/js/` +- The `jsdom` test environment for DOM and browser API access +- Path exclusions for Drupal core, contrib modules, and themes + +## Writing tests + +Drupal JavaScript uses the IIFE pattern `((Drupal) => { ... })(Drupal)` where +`Drupal` is a global object. Jest tests load these files by: + +1. Setting `global.Drupal = { behaviors: {} }` in `beforeEach` +2. Reading and executing the source file with `eval(fs.readFileSync(...))` +3. Accessing the registered behavior via `Drupal.behaviors.myModule` +4. Cleaning up with `delete global.Drupal` in `afterEach` + +This approach allows testing Drupal behaviors without a browser or Drupal +bootstrap, while keeping the source files unchanged. + +## Boilerplate + +**Vortex** provides a Jest test boilerplate for the [demo module](https://github.com/drevops/vortex/blob/main/web/modules/custom/ys_demo/js/ys_demo.test.js) +that demonstrates testing a counter block with DOM manipulation, localStorage +interaction, and event handling. + +This boilerplate test runs in continuous integration pipeline when you install +**Vortex** and can be used as a starting point for writing your own JavaScript +tests. diff --git a/.vortex/docs/content/tools/jest.mdx b/.vortex/docs/content/tools/jest.mdx new file mode 100644 index 000000000..8cee697ef --- /dev/null +++ b/.vortex/docs/content/tools/jest.mdx @@ -0,0 +1,168 @@ +--- +sidebar_label: Jest +--- + +# Jest – JavaScript Testing Framework + +https://jestjs.io/ + +> Jest is a delightful JavaScript testing framework with a focus on simplicity. + +**Vortex** comes with [pre-configured Jest setup](https://github.com/drevops/vortex/blob/main/jest.config.js) for testing JavaScript in custom Drupal modules. + +## Usage + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + ```shell + ahoy test-js # Run all Jest tests. + ``` + + + ```shell + docker compose exec cli bash -c "yarn test" # Run all Jest tests. + ``` + + + +### Running tests matching a pattern + + + + ```shell + ahoy test-js -- --testPathPattern=ys_demo + ``` + + + ```shell + docker compose exec cli bash -c "yarn test --testPathPattern=ys_demo" + ``` + + + +### Running a specific test by name + + + + ```shell + ahoy test-js -- -t "should increment the value" + ``` + + + ```shell + docker compose exec cli bash -c "yarn test -t 'should increment the value'" + ``` + + + +## Configuration + +See [Jest configuration reference](https://jestjs.io/docs/configuration). + +All global configuration takes place in the [`jest.config.js`](https://github.com/drevops/vortex/blob/main/jest.config.js) file. + +By default, Jest will discover and run test files in `web/modules/custom/*/js/` +directories. Test files must use the `.test.js` extension and be co-located +alongside the source files they test. + +The configuration uses the `jsdom` test environment to provide browser globals +like `document`, `window`, and `localStorage`. + +### Test discovery + +The `jest.config.js` file dynamically scans `web/modules/custom/` for modules +that contain a `js/` directory, and adds each as a root for test discovery. This +means adding a new custom module with JavaScript tests requires no configuration +changes. + +## Writing tests + +Test files are placed next to the source file they test: + +```text +web/modules/custom/my_module/ +└── js/ + ├── my_module.js # Source file + └── my_module.test.js # Test file +``` + +### Loading Drupal behaviors + +Drupal JavaScript uses the IIFE pattern with `Drupal` as a global. Tests load +the source file using `eval()` after setting up the global: + +```javascript +/** + * @jest-environment jsdom + */ + +const fs = require('fs'); +const path = require('path'); + +describe('Drupal.behaviors.myModule', () => { + beforeEach(() => { + localStorage.clear(); + global.Drupal = { behaviors: {} }; + + const filePath = path.resolve(__dirname, 'my_module.js'); + const code = fs.readFileSync(filePath, 'utf8'); + eval(code); + }); + + afterEach(() => { + delete global.Drupal; + }); + + it('should attach behavior', () => { + document.body.innerHTML = '
'; + Drupal.behaviors.myModule.attach(document); + + const el = document.querySelector('[data-my-module]'); + expect(el.classList.contains('processed')).toBe(true); + }); +}); +``` + +### Key patterns + +- **`global.Drupal = { behaviors: {} }`** in `beforeEach` provides the Drupal + global that the IIFE receives as a parameter. +- **`eval(fs.readFileSync(...))`** loads and executes the source file, which + registers the behavior on `Drupal.behaviors`. +- **`delete global.Drupal`** in `afterEach` ensures test isolation. +- **`document.body.innerHTML`** sets up the DOM for each test using jsdom. +- **`jest.useFakeTimers()`** controls `setTimeout` and `setInterval` for + testing timed behavior. + +### ESLint configuration + +The `.eslintrc.json` file includes an override for `*.test.js` files that +enables the `jest` environment and disables `no-eval` to allow the source +loading pattern: + +```json +{ + "overrides": [ + { + "files": ["*.test.js"], + "env": { "jest": true }, + "rules": { + "no-eval": "off", + "max-nested-callbacks": ["warn", 5], + "jsdoc/check-tag-names": "off" + } + } + ] +} +``` + +## Ignoring fail in continuous integration pipeline + +This tool runs in continuous integration pipeline by default and fails the build +if there are any violations. + +Set `VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE` environment variable to `1` to ignore +failures. The tool will still run and report violations, if any. From 88f37768da24e6e932b522c36f3e980333057d0d Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 15:24:09 +1100 Subject: [PATCH 30/36] [#2394] Added Jest workflow test for pass, path pattern, and failure scenarios. --- .../phpunit/Functional/AhoyWorkflowTest.php | 2 ++ .../Traits/Subtests/SubtestAhoyTrait.php | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php b/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php index 26d79756a..52c549103 100644 --- a/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php +++ b/.vortex/tests/phpunit/Functional/AhoyWorkflowTest.php @@ -102,6 +102,8 @@ public function testAhoyWorkflowStateful(): void { $this->subtestAhoyTestFunctionalJavascript(); + $this->subtestAhoyTestJs(); + $this->subtestAhoyTestBdd(); // Run this test as a last one to make sure that there is no concurrency diff --git a/.vortex/tests/phpunit/Traits/Subtests/SubtestAhoyTrait.php b/.vortex/tests/phpunit/Traits/Subtests/SubtestAhoyTrait.php index d8885e28d..db6412a08 100644 --- a/.vortex/tests/phpunit/Traits/Subtests/SubtestAhoyTrait.php +++ b/.vortex/tests/phpunit/Traits/Subtests/SubtestAhoyTrait.php @@ -533,6 +533,30 @@ protected function runAhoyTestPhpunit(string $type, string $file): void { $this->removePathHostAndContainer('.logs'); } + protected function subtestAhoyTestJs(string $webroot = 'web'): void { + $this->logStepStart(); + + $file = $webroot . '/modules/custom/sw_demo/js/sw_demo.test.js'; + $this->assertFileExists($file); + + $this->logSubstep('Run all Jest tests'); + $this->cmd('ahoy test-js', 'Tests:'); + $this->logSubstep('Run Jest tests matching a path pattern'); + $this->cmd('ahoy test-js -- --testPathPattern=sw_demo', 'Tests:'); + + $this->logSubstep('Assert that Jest test failure works'); + $this->fileBackup($file); + File::replaceContentInFile($file, 'toBe(true)', 'toBe(false)'); + $this->syncToContainer($file); + + $this->cmdFail('ahoy test-js'); + + $this->fileRestore($file); + $this->syncToContainer($file); + + $this->logStepFinish(); + } + protected function subtestAhoyTestBdd(string $webroot = 'web'): void { $this->logStepStart(); From a20194529cde934c0bac546190296678c1a61e87 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 15:27:58 +1100 Subject: [PATCH 31/36] [#2394] Added test-by-name scenario to Jest workflow test. --- .vortex/tests/phpunit/Traits/Subtests/SubtestAhoyTrait.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.vortex/tests/phpunit/Traits/Subtests/SubtestAhoyTrait.php b/.vortex/tests/phpunit/Traits/Subtests/SubtestAhoyTrait.php index db6412a08..d4c12f015 100644 --- a/.vortex/tests/phpunit/Traits/Subtests/SubtestAhoyTrait.php +++ b/.vortex/tests/phpunit/Traits/Subtests/SubtestAhoyTrait.php @@ -541,14 +541,17 @@ protected function subtestAhoyTestJs(string $webroot = 'web'): void { $this->logSubstep('Run all Jest tests'); $this->cmd('ahoy test-js', 'Tests:'); + $this->logSubstep('Run Jest tests matching a path pattern'); $this->cmd('ahoy test-js -- --testPathPattern=sw_demo', 'Tests:'); + $this->logSubstep('Run a specific Jest test by name'); + $this->cmd('ahoy test-js -- -t "should have the expected storage key"', 'Tests:'); + $this->logSubstep('Assert that Jest test failure works'); $this->fileBackup($file); File::replaceContentInFile($file, 'toBe(true)', 'toBe(false)'); $this->syncToContainer($file); - $this->cmdFail('ahoy test-js'); $this->fileRestore($file); From cbfa2601207b630acc4936746fe30f45bd1335d4 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 15:36:17 +1100 Subject: [PATCH 32/36] [#2394] Refocused development Jest docs on writing tests, linked to tools page. --- .vortex/docs/content/development/jest.mdx | 136 ++++++++++++------ .../.!!k2C/.docker/cli.dockerfile | 9 -- .../.!!k2C/.docker/nginx-drupal.dockerfile | 9 -- .../handler_process/.!!k2C/.env.local.example | 12 -- .../handler_process/.!!k2C/phpunit.xml | 66 --------- .../handler_process/.!!k2C/web/-autoload.php | 0 .../custom/sw_demo/-sw_demo.deploy.php | 0 .../modules/custom/sw_demo/-sw_demo.info.yml | 0 .../custom/sw_demo/-sw_demo.libraries.yml | 0 .../modules/custom/sw_demo/-sw_demo.module | 0 .../install/-views.view.sw_demo_articles.yml | 0 .../modules/custom/sw_demo/css/-sw_demo.css | 0 .../web/modules/custom/sw_demo/js/-sw_demo.js | 0 .../src/Plugin/Block/-CounterBlock.php | 0 .../Plugin/GeneratedContent/Node/-Article.php | 0 .../GeneratedContent/Taxonomy/-Tags.php | 0 .../-sw-demo-counter-block.html.twig | 0 .../-CounterBlockTest.php | 0 .../tests/src/Kernel/-CounterBlockTest.php | 0 .../tests/src/Unit/-CounterBlockTest.php | 0 .../web/sites/default/-default.services.yml | 0 .../web/sites/default/-default.settings.php | 0 .../sites/default/-example.services.local.yml | 0 .../sites/default/-example.settings.local.php | 0 .../.!!k2C/web/sites/default/-services.yml | 0 .../.!!k2C/web/sites/default/-settings.php | 0 .../modules/-settings.automated_cron.php | 0 .../includes/modules/-settings.clamav.php | 0 .../modules/-settings.config_split.php | 0 .../-settings.environment_indicator.php | 0 .../includes/modules/-settings.fast404.php | 0 .../includes/modules/-settings.redis.php | 0 .../includes/modules/-settings.robotstxt.php | 0 .../includes/modules/-settings.seckit.php | 0 .../includes/modules/-settings.shield.php | 0 .../modules/-settings.stage_file_proxy.php | 0 .../includes/modules/-settings.sw_base.php | 0 .../includes/modules/-settings.system.php | 0 .../modules/-settings.trusted_hosts.php | 0 .../includes/modules/-settings.xmlsitemap.php | 0 .../providers/-settings.container.php | 0 .../includes/providers/-settings.gha.php | 0 42 files changed, 92 insertions(+), 140 deletions(-) delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/.docker/cli.dockerfile delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/.docker/nginx-drupal.dockerfile delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/.env.local.example delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/phpunit.xml delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/-autoload.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.deploy.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.info.yml delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.libraries.yml delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.module delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/config/install/-views.view.sw_demo_articles.yml delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/css/-sw_demo.css delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/js/-sw_demo.js delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/src/Plugin/Block/-CounterBlock.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/src/Plugin/GeneratedContent/Node/-Article.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/src/Plugin/GeneratedContent/Taxonomy/-Tags.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/templates/-sw-demo-counter-block.html.twig delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/tests/src/FunctionalJavascript/-CounterBlockTest.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/tests/src/Kernel/-CounterBlockTest.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/tests/src/Unit/-CounterBlockTest.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-default.services.yml delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-default.settings.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-example.services.local.yml delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-example.settings.local.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-services.yml delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-settings.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.automated_cron.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.clamav.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.config_split.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.environment_indicator.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.fast404.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.redis.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.robotstxt.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.seckit.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.shield.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.stage_file_proxy.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.sw_base.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.system.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.trusted_hosts.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.xmlsitemap.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/providers/-settings.container.php delete mode 100644 .vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/providers/-settings.gha.php diff --git a/.vortex/docs/content/development/jest.mdx b/.vortex/docs/content/development/jest.mdx index d910218ac..e340005db 100644 --- a/.vortex/docs/content/development/jest.mdx +++ b/.vortex/docs/content/development/jest.mdx @@ -9,36 +9,8 @@ sidebar_position: 6 testing. Jest tests verify that JavaScript behaviors in custom Drupal modules work correctly in isolation, without requiring a browser or Drupal bootstrap. -**Vortex** provides Jest support with configuration in [`jest.config.js`](https://github.com/drevops/vortex/blob/main/jest.config.js) -that automatically discovers test files in custom modules. - -## Running tests - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - - - - ```shell - # Run all Jest tests - ahoy test-js - # Run tests matching a pattern - ahoy test-js -- --testPathPattern=ys_demo - # Run a specific test by name - ahoy test-js -- -t "should increment the value" - ``` - - - ```shell - # Run all Jest tests - docker compose exec cli bash -c "yarn test" - # Run tests matching a pattern - docker compose exec cli bash -c "yarn test --testPathPattern=ys_demo" - # Run a specific test by name - docker compose exec cli bash -c "yarn test -t 'should increment the value'" - ``` - - +For running tests, configuration, and CI settings, see the +[Jest tool reference](/tools/jest). ## Test file structure @@ -55,26 +27,102 @@ web/modules/custom/my_module/ Jest automatically discovers `*.test.js` files in `web/modules/custom/*/js/` directories. Adding a new module with tests requires no configuration changes. -## Configuration +## Writing tests -The `jest.config.js` file in the project root configures: +Drupal JavaScript uses the IIFE pattern `((Drupal) => { ... })(Drupal)` where +`Drupal` is a global object. Tests load these source files using `eval()` after +setting up the required globals. -- Dynamic root discovery scanning `web/modules/custom/*/js/` -- The `jsdom` test environment for DOM and browser API access -- Path exclusions for Drupal core, contrib modules, and themes +### Test template -## Writing tests +```javascript +/** + * @jest-environment jsdom + */ -Drupal JavaScript uses the IIFE pattern `((Drupal) => { ... })(Drupal)` where -`Drupal` is a global object. Jest tests load these files by: +const fs = require('fs'); +const path = require('path'); + +describe('Drupal.behaviors.myModule', () => { + beforeEach(() => { + localStorage.clear(); + global.Drupal = { behaviors: {} }; + + const filePath = path.resolve(__dirname, 'my_module.js'); + const code = fs.readFileSync(filePath, 'utf8'); + eval(code); + }); + + afterEach(() => { + delete global.Drupal; + }); + + it('should attach behavior to the context', () => { + document.body.innerHTML = '
'; + Drupal.behaviors.myModule.attach(document); + + const el = document.querySelector('[data-my-module]'); + expect(el.classList.contains('processed')).toBe(true); + }); +}); +``` + +### Loading Drupal behaviors + +The `eval(fs.readFileSync(...))` pattern executes the source file's IIFE, which +receives `global.Drupal` as its `Drupal` parameter and registers the behavior. +After `eval()`, the behavior is accessible via `Drupal.behaviors.myModule`. + +### Mocking globals + +Set globals in `beforeEach` and clean them up in `afterEach`: + +| Global | Setup | When needed | +|--------|-------|-------------| +| `Drupal` | `global.Drupal = { behaviors: {} }` | Always — required by all Drupal behaviors | +| `jQuery` | `global.jQuery = require('jquery')` or a mock | When the source file uses `jQuery` or `$` | +| `drupalSettings` | `global.drupalSettings = { path: { baseUrl: '/' } }` | When the source file reads `drupalSettings` | +| `localStorage` | Provided by jsdom; call `localStorage.clear()` | When the source file uses `localStorage` | + +### Testing DOM interactions + +The `jsdom` environment provides `document` and `window`. Set up HTML before +each test: + +```javascript +document.body.innerHTML = ` +
+ + +
+`; + +Drupal.behaviors.myModule.attach(document); +document.querySelector('[data-action="save"]').click(); + +expect(document.querySelector('[data-status]').textContent).toBe('Saved'); +``` + +### Testing timed behavior + +Use Jest fake timers for `setTimeout` and `setInterval`: + +```javascript +jest.useFakeTimers(); + +Drupal.behaviors.myModule.startPolling(); +jest.advanceTimersByTime(5000); + +expect(fetchSpy).toHaveBeenCalledTimes(5); + +jest.useRealTimers(); +``` -1. Setting `global.Drupal = { behaviors: {} }` in `beforeEach` -2. Reading and executing the source file with `eval(fs.readFileSync(...))` -3. Accessing the registered behavior via `Drupal.behaviors.myModule` -4. Cleaning up with `delete global.Drupal` in `afterEach` +### ESLint compatibility -This approach allows testing Drupal behaviors without a browser or Drupal -bootstrap, while keeping the source files unchanged. +The `.eslintrc.json` includes an override for `*.test.js` files that enables +the `jest` environment and allows `eval()`. No additional ESLint configuration +is needed for test files. ## Boilerplate diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/.docker/cli.dockerfile b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/.docker/cli.dockerfile deleted file mode 100644 index 399d0eee7..000000000 --- a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/.docker/cli.dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -@@ -16,7 +16,7 @@ - ARG LAGOON_PR_HEAD_SHA="" - ENV LAGOON_PR_HEAD_SHA=${LAGOON_PR_HEAD_SHA} - --ARG WEBROOT=web -+ARG WEBROOT=docroot - ENV WEBROOT=${WEBROOT} - - # Token is used to access private repositories. Not exposed as an environment diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/.docker/nginx-drupal.dockerfile b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/.docker/nginx-drupal.dockerfile deleted file mode 100644 index 7d6c276fd..000000000 --- a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/.docker/nginx-drupal.dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -@@ -14,7 +14,7 @@ - FROM uselagoon/nginx-drupal:__VERSION__ - - # Webroot is used for Nginx web root configuration. --ARG WEBROOT=web -+ARG WEBROOT=docroot - ENV WEBROOT=${WEBROOT} - - RUN apk add --no-cache tzdata diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/.env.local.example b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/.env.local.example deleted file mode 100644 index fa1beee41..000000000 --- a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/.env.local.example +++ /dev/null @@ -1,12 +0,0 @@ -@@ -32,3 +32,11 @@ - - # Always override existing downloaded DB dump. - VORTEX_DOWNLOAD_DB_FORCE=1 -+ -+# Database dump file sourced from Acquia. -+# Acquia Cloud API token: Acquia Cloud UI -> Account -> API tokens -> Create Token -+ -+# Acquia Cloud API key. -+VORTEX_ACQUIA_KEY= -+# Acquia Cloud API secret. -+VORTEX_ACQUIA_SECRET= diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/phpunit.xml b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/phpunit.xml deleted file mode 100644 index ec09a29da..000000000 --- a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/phpunit.xml +++ /dev/null @@ -1,66 +0,0 @@ -@@ -66,21 +66,21 @@ - - - tests/phpunit -- web/modules/custom/**/tests/src/Unit -- web/themes/custom/**/tests/src/Unit -+ docroot/modules/custom/**/tests/src/Unit -+ docroot/themes/custom/**/tests/src/Unit - - -- web/modules/custom/**/tests/src/Kernel -- web/themes/custom/**/tests/src/Kernel -+ docroot/modules/custom/**/tests/src/Kernel -+ docroot/themes/custom/**/tests/src/Kernel - - -- web/modules/custom/**/tests/src/Functional -- web/themes/custom/**/tests/src/Functional -+ docroot/modules/custom/**/tests/src/Functional -+ docroot/themes/custom/**/tests/src/Functional - - - -- web/modules/custom/**/tests/src/FunctionalJavascript -- web/themes/custom/**/tests/src/FunctionalJavascript -+ docroot/modules/custom/**/tests/src/FunctionalJavascript -+ docroot/themes/custom/**/tests/src/FunctionalJavascript - - - -@@ -101,17 +101,17 @@ - - - -- web/modules/custom -- web/themes/custom -- web/sites/default/includes -- web/sites/default/settings.php -+ docroot/modules/custom -+ docroot/themes/custom -+ docroot/sites/default/includes -+ docroot/sites/default/settings.php - - -- web/modules/custom -- web/modules/custom -- web/modules/custom/**/node_modules -- web/themes/custom -- web/themes/custom/**/node_modules -+ docroot/modules/custom -+ docroot/modules/custom -+ docroot/modules/custom/**/node_modules -+ docroot/themes/custom -+ docroot/themes/custom/**/node_modules - tests - - -@@ -127,7 +127,7 @@ - to DRUPAL_ROOT/sites/simpletest/browser_output. - @see https://www.drupal.org/project/drupal/issues/2992069 --> - -- -+ - - - diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/-autoload.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/-autoload.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.deploy.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.deploy.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.info.yml b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.info.yml deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.libraries.yml b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.libraries.yml deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.module b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/-sw_demo.module deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/config/install/-views.view.sw_demo_articles.yml b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/config/install/-views.view.sw_demo_articles.yml deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/css/-sw_demo.css b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/css/-sw_demo.css deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/js/-sw_demo.js b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/js/-sw_demo.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/src/Plugin/Block/-CounterBlock.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/src/Plugin/Block/-CounterBlock.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/src/Plugin/GeneratedContent/Node/-Article.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/src/Plugin/GeneratedContent/Node/-Article.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/src/Plugin/GeneratedContent/Taxonomy/-Tags.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/src/Plugin/GeneratedContent/Taxonomy/-Tags.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/templates/-sw-demo-counter-block.html.twig b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/templates/-sw-demo-counter-block.html.twig deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/tests/src/FunctionalJavascript/-CounterBlockTest.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/tests/src/FunctionalJavascript/-CounterBlockTest.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/tests/src/Kernel/-CounterBlockTest.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/tests/src/Kernel/-CounterBlockTest.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/tests/src/Unit/-CounterBlockTest.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/modules/custom/sw_demo/tests/src/Unit/-CounterBlockTest.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-default.services.yml b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-default.services.yml deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-default.settings.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-default.settings.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-example.services.local.yml b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-example.services.local.yml deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-example.settings.local.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-example.settings.local.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-services.yml b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-services.yml deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-settings.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/-settings.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.automated_cron.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.automated_cron.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.clamav.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.clamav.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.config_split.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.config_split.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.environment_indicator.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.environment_indicator.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.fast404.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.fast404.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.redis.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.redis.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.robotstxt.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.robotstxt.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.seckit.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.seckit.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.shield.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.shield.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.stage_file_proxy.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.stage_file_proxy.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.sw_base.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.sw_base.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.system.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.system.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.trusted_hosts.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.trusted_hosts.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.xmlsitemap.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/modules/-settings.xmlsitemap.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/providers/-settings.container.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/providers/-settings.container.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/providers/-settings.gha.php b/.vortex/installer/tests/Fixtures/handler_process/.!!k2C/web/sites/default/includes/providers/-settings.gha.php deleted file mode 100644 index e69de29bb..000000000 From eea6d1f0d6f0df440f3b4ead72dc67fdd4e4e6a6 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 15:42:06 +1100 Subject: [PATCH 33/36] [#2394] Renamed CI var to VORTEX_CI_JEST_IGNORE_FAILURE and cross-linked docs. --- .circleci/config.yml | 2 +- .circleci/vortex-test-common.yml | 2 +- .github/workflows/build-test-deploy.yml | 2 +- .vortex/docs/content/tools/jest.mdx | 5 ++++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5d44de827..534026ed3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -386,7 +386,7 @@ jobs: #;< TOOL_JEST - run: name: Test with Jest - command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_JEST_IGNORE_FAILURE:-0}" -eq 1 ] #;> TOOL_JEST #;< TOOL_PHPUNIT diff --git a/.circleci/vortex-test-common.yml b/.circleci/vortex-test-common.yml index ea6281b29..cbdb17bc9 100644 --- a/.circleci/vortex-test-common.yml +++ b/.circleci/vortex-test-common.yml @@ -252,7 +252,7 @@ jobs: #;< TOOL_JEST - run: name: Test with Jest - command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_JEST_IGNORE_FAILURE:-0}" -eq 1 ] #;> TOOL_JEST #;< TOOL_PHPUNIT diff --git a/.github/workflows/build-test-deploy.yml b/.github/workflows/build-test-deploy.yml index d317b73d1..e4350b788 100644 --- a/.github/workflows/build-test-deploy.yml +++ b/.github/workflows/build-test-deploy.yml @@ -430,7 +430,7 @@ jobs: - name: Test with Jest if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} run: docker compose exec -T cli bash -c "yarn test" - continue-on-error: ${{ vars.VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE == '1' }} + continue-on-error: ${{ vars.VORTEX_CI_JEST_IGNORE_FAILURE == '1' }} #;> TOOL_JEST #;< TOOL_PHPUNIT diff --git a/.vortex/docs/content/tools/jest.mdx b/.vortex/docs/content/tools/jest.mdx index 8cee697ef..d18d0f1a6 100644 --- a/.vortex/docs/content/tools/jest.mdx +++ b/.vortex/docs/content/tools/jest.mdx @@ -10,6 +10,9 @@ https://jestjs.io/ **Vortex** comes with [pre-configured Jest setup](https://github.com/drevops/vortex/blob/main/jest.config.js) for testing JavaScript in custom Drupal modules. +For writing tests, mocking Drupal globals, and test templates, see the +[Jest development guide](/development/jest). + ## Usage import Tabs from '@theme/Tabs'; @@ -164,5 +167,5 @@ loading pattern: This tool runs in continuous integration pipeline by default and fails the build if there are any violations. -Set `VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE` environment variable to `1` to ignore +Set `VORTEX_CI_JEST_IGNORE_FAILURE` environment variable to `1` to ignore failures. The tool will still run and report violations, if any. From 0c4482e3ae3e71e94ed29e06d722001e7e2e130e Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 15:42:27 +1100 Subject: [PATCH 34/36] Updated snapshots. --- .../_baseline/.github/workflows/build-test-deploy.yml | 2 +- .../handler_process/ciprovider_circleci/.circleci/config.yml | 2 +- .../deploy_types_all_circleci/.circleci/config.yml | 2 +- .../deploy_types_none_circleci/.circleci/config.yml | 2 +- .../deps_updates_provider_ci_circleci/.circleci/config.yml | 2 +- .../migration_disabled_circleci/.circleci/config.yml | 2 +- .../migration_enabled_circleci/.circleci/config.yml | 2 +- .../handler_process/timezone_circleci/.circleci/config.yml | 2 +- .../tools_groups_no_be_lint_circleci/.circleci/config.yml | 2 +- .../.github/workflows/build-test-deploy.yml | 2 +- .../tools_groups_no_be_tests_circleci/.circleci/config.yml | 2 +- .../.github/workflows/build-test-deploy.yml | 2 +- .../.github/workflows/build-test-deploy.yml | 2 +- .../tools_no_behat_circleci/.circleci/config.yml | 2 +- .../tools_no_eslint_circleci/.circleci/config.yml | 2 +- .../tools_no_jest/.github/workflows/build-test-deploy.yml | 2 +- .../tools_no_phpcs_circleci/.circleci/config.yml | 2 +- .../tools_no_phpmd_circleci/.circleci/config.yml | 2 +- .../tools_no_phpstan_circleci/.circleci/config.yml | 2 +- .../tools_no_phpunit/.github/workflows/build-test-deploy.yml | 2 +- .../tools_no_phpunit_circleci/.circleci/config.yml | 2 +- .../tools_no_rector_circleci/.circleci/config.yml | 2 +- .../tools_no_stylelint_circleci/.circleci/config.yml | 2 +- .../tools_none/.github/workflows/build-test-deploy.yml | 2 +- 24 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.vortex/installer/tests/Fixtures/handler_process/_baseline/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/_baseline/.github/workflows/build-test-deploy.yml index 82f93f2df..d6b75b1cb 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/_baseline/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/_baseline/.github/workflows/build-test-deploy.yml @@ -380,7 +380,7 @@ jobs: - name: Test with Jest if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} run: docker compose exec -T cli bash -c "yarn test" - continue-on-error: ${{ vars.VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE == '1' }} + continue-on-error: ${{ vars.VORTEX_CI_JEST_IGNORE_FAILURE == '1' }} - name: Test with PHPUnit if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} diff --git a/.vortex/installer/tests/Fixtures/handler_process/ciprovider_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/ciprovider_circleci/.circleci/config.yml index 16659c5c8..2845230c7 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/ciprovider_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/ciprovider_circleci/.circleci/config.yml @@ -339,7 +339,7 @@ jobs: - run: name: Test with Jest - command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_JEST_IGNORE_FAILURE:-0}" -eq 1 ] - run: name: Test with PHPUnit diff --git a/.vortex/installer/tests/Fixtures/handler_process/deploy_types_all_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/deploy_types_all_circleci/.circleci/config.yml index 16659c5c8..2845230c7 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/deploy_types_all_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/deploy_types_all_circleci/.circleci/config.yml @@ -339,7 +339,7 @@ jobs: - run: name: Test with Jest - command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_JEST_IGNORE_FAILURE:-0}" -eq 1 ] - run: name: Test with PHPUnit diff --git a/.vortex/installer/tests/Fixtures/handler_process/deploy_types_none_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/deploy_types_none_circleci/.circleci/config.yml index 2198bd30a..ca771ee23 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/deploy_types_none_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/deploy_types_none_circleci/.circleci/config.yml @@ -339,7 +339,7 @@ jobs: - run: name: Test with Jest - command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_JEST_IGNORE_FAILURE:-0}" -eq 1 ] - run: name: Test with PHPUnit diff --git a/.vortex/installer/tests/Fixtures/handler_process/deps_updates_provider_ci_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/deps_updates_provider_ci_circleci/.circleci/config.yml index 16659c5c8..2845230c7 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/deps_updates_provider_ci_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/deps_updates_provider_ci_circleci/.circleci/config.yml @@ -339,7 +339,7 @@ jobs: - run: name: Test with Jest - command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_JEST_IGNORE_FAILURE:-0}" -eq 1 ] - run: name: Test with PHPUnit diff --git a/.vortex/installer/tests/Fixtures/handler_process/migration_disabled_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/migration_disabled_circleci/.circleci/config.yml index 16659c5c8..2845230c7 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/migration_disabled_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/migration_disabled_circleci/.circleci/config.yml @@ -339,7 +339,7 @@ jobs: - run: name: Test with Jest - command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_JEST_IGNORE_FAILURE:-0}" -eq 1 ] - run: name: Test with PHPUnit diff --git a/.vortex/installer/tests/Fixtures/handler_process/migration_enabled_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/migration_enabled_circleci/.circleci/config.yml index f36cc4b94..f4111360d 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/migration_enabled_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/migration_enabled_circleci/.circleci/config.yml @@ -348,7 +348,7 @@ jobs: - run: name: Test with Jest - command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_JEST_IGNORE_FAILURE:-0}" -eq 1 ] - run: name: Test with PHPUnit diff --git a/.vortex/installer/tests/Fixtures/handler_process/timezone_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/timezone_circleci/.circleci/config.yml index 16659c5c8..2845230c7 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/timezone_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/timezone_circleci/.circleci/config.yml @@ -339,7 +339,7 @@ jobs: - run: name: Test with Jest - command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_JEST_IGNORE_FAILURE:-0}" -eq 1 ] - run: name: Test with PHPUnit diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_lint_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_lint_circleci/.circleci/config.yml index 9bbfb5413..3246c1ca1 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_lint_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_lint_circleci/.circleci/config.yml @@ -323,7 +323,7 @@ jobs: - run: name: Test with Jest - command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_JEST_IGNORE_FAILURE:-0}" -eq 1 ] - run: name: Test with PHPUnit diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests/.github/workflows/build-test-deploy.yml index 57b4caa63..8900db508 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests/.github/workflows/build-test-deploy.yml @@ -12,7 +12,7 @@ @@ -381,88 +377,6 @@ if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} run: docker compose exec -T cli bash -c "yarn test" - continue-on-error: ${{ vars.VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE == '1' }} + continue-on-error: ${{ vars.VORTEX_CI_JEST_IGNORE_FAILURE == '1' }} - - - name: Test with PHPUnit - if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests_circleci/.circleci/config.yml index 84f3ef566..0c6fe1dc3 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_be_tests_circleci/.circleci/config.yml @@ -335,7 +335,7 @@ jobs: - run: name: Test with Jest - command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_JEST_IGNORE_FAILURE:-0}" -eq 1 ] - run: name: Process test logs and artifacts diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/.github/workflows/build-test-deploy.yml index 88fa6ad1b..cd6c04bf2 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint/.github/workflows/build-test-deploy.yml @@ -33,7 +33,7 @@ - - name: Test with Jest - if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} - run: docker compose exec -T cli bash -c "yarn test" -- continue-on-error: ${{ vars.VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE == '1' }} +- continue-on-error: ${{ vars.VORTEX_CI_JEST_IGNORE_FAILURE == '1' }} - name: Test with PHPUnit if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/.github/workflows/build-test-deploy.yml index 1430c7bb8..fd0b226e7 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_groups_no_fe_lint_no_theme/.github/workflows/build-test-deploy.yml @@ -38,7 +38,7 @@ - - name: Test with Jest - if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} - run: docker compose exec -T cli bash -c "yarn test" -- continue-on-error: ${{ vars.VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE == '1' }} +- continue-on-error: ${{ vars.VORTEX_CI_JEST_IGNORE_FAILURE == '1' }} - name: Test with PHPUnit if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat_circleci/.circleci/config.yml index 5017a2f71..3fc5671a8 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_behat_circleci/.circleci/config.yml @@ -335,7 +335,7 @@ jobs: - run: name: Test with Jest - command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_JEST_IGNORE_FAILURE:-0}" -eq 1 ] - run: name: Test with PHPUnit diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_circleci/.circleci/config.yml index 35d3702e2..a8e17f5b9 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_eslint_circleci/.circleci/config.yml @@ -334,7 +334,7 @@ jobs: - run: name: Test with Jest - command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_JEST_IGNORE_FAILURE:-0}" -eq 1 ] - run: name: Test with PHPUnit diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/.github/workflows/build-test-deploy.yml index 8a85d8e7f..b77d72e2d 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_jest/.github/workflows/build-test-deploy.yml @@ -14,7 +14,7 @@ - - name: Test with Jest - if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} - run: docker compose exec -T cli bash -c "yarn test" -- continue-on-error: ${{ vars.VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE == '1' }} +- continue-on-error: ${{ vars.VORTEX_CI_JEST_IGNORE_FAILURE == '1' }} - name: Test with PHPUnit if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpcs_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpcs_circleci/.circleci/config.yml index 9fb1171fd..4b75e6a94 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpcs_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpcs_circleci/.circleci/config.yml @@ -335,7 +335,7 @@ jobs: - run: name: Test with Jest - command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_JEST_IGNORE_FAILURE:-0}" -eq 1 ] - run: name: Test with PHPUnit diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpmd_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpmd_circleci/.circleci/config.yml index 80bcb69e7..bce30465c 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpmd_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpmd_circleci/.circleci/config.yml @@ -335,7 +335,7 @@ jobs: - run: name: Test with Jest - command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_JEST_IGNORE_FAILURE:-0}" -eq 1 ] - run: name: Test with PHPUnit diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpstan_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpstan_circleci/.circleci/config.yml index 996ae2b89..bcaebe2df 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpstan_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpstan_circleci/.circleci/config.yml @@ -335,7 +335,7 @@ jobs: - run: name: Test with Jest - command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_JEST_IGNORE_FAILURE:-0}" -eq 1 ] - run: name: Test with PHPUnit diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpunit/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpunit/.github/workflows/build-test-deploy.yml index 35a69088e..0a7e07b1d 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpunit/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpunit/.github/workflows/build-test-deploy.yml @@ -1,6 +1,6 @@ @@ -382,76 +382,6 @@ run: docker compose exec -T cli bash -c "yarn test" - continue-on-error: ${{ vars.VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE == '1' }} + continue-on-error: ${{ vars.VORTEX_CI_JEST_IGNORE_FAILURE == '1' }} - - name: Test with PHPUnit - if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpunit_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpunit_circleci/.circleci/config.yml index 74decb0a1..23fb012da 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpunit_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_phpunit_circleci/.circleci/config.yml @@ -339,7 +339,7 @@ jobs: - run: name: Test with Jest - command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_JEST_IGNORE_FAILURE:-0}" -eq 1 ] - run: name: Test with Behat diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_rector_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_no_rector_circleci/.circleci/config.yml index ad5d1296e..9b8d352af 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_rector_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_rector_circleci/.circleci/config.yml @@ -335,7 +335,7 @@ jobs: - run: name: Test with Jest - command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_JEST_IGNORE_FAILURE:-0}" -eq 1 ] - run: name: Test with PHPUnit diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_circleci/.circleci/config.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_circleci/.circleci/config.yml index 16659c5c8..2845230c7 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_circleci/.circleci/config.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_no_stylelint_circleci/.circleci/config.yml @@ -339,7 +339,7 @@ jobs: - run: name: Test with Jest - command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE:-0}" -eq 1 ] + command: docker compose exec -T cli bash -c "yarn test" || [ "${VORTEX_CI_JEST_IGNORE_FAILURE:-0}" -eq 1 ] - run: name: Test with PHPUnit diff --git a/.vortex/installer/tests/Fixtures/handler_process/tools_none/.github/workflows/build-test-deploy.yml b/.vortex/installer/tests/Fixtures/handler_process/tools_none/.github/workflows/build-test-deploy.yml index e7aa3b64f..af947edae 100644 --- a/.vortex/installer/tests/Fixtures/handler_process/tools_none/.github/workflows/build-test-deploy.yml +++ b/.vortex/installer/tests/Fixtures/handler_process/tools_none/.github/workflows/build-test-deploy.yml @@ -58,7 +58,7 @@ - - name: Test with Jest - if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} - run: docker compose exec -T cli bash -c "yarn test" -- continue-on-error: ${{ vars.VORTEX_CI_NODEJS_TEST_IGNORE_FAILURE == '1' }} +- continue-on-error: ${{ vars.VORTEX_CI_JEST_IGNORE_FAILURE == '1' }} - - - name: Test with PHPUnit - if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} From 12966047ff7410f5bc63c4d2b9dd14e8e919aebf Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 15:50:54 +1100 Subject: [PATCH 35/36] [#2394] Added VORTEX_CI_JEST_IGNORE_FAILURE to CI variables and updated docs. --- .vortex/docs/.utils/variables/extra/ci.variables.sh | 3 +++ .vortex/docs/content/development/variables.mdx | 1 + 2 files changed, 4 insertions(+) diff --git a/.vortex/docs/.utils/variables/extra/ci.variables.sh b/.vortex/docs/.utils/variables/extra/ci.variables.sh index c2fe6bae2..bdee75805 100755 --- a/.vortex/docs/.utils/variables/extra/ci.variables.sh +++ b/.vortex/docs/.utils/variables/extra/ci.variables.sh @@ -69,6 +69,9 @@ VORTEX_CI_BEHAT_IGNORE_FAILURE=0 # Test Behat profile to use in CI. If not set, the `default` profile will be used. VORTEX_CI_BEHAT_PROFILE= +# Ignore Jest test failures. +VORTEX_CI_JEST_IGNORE_FAILURE=0 + # Directory to store test results in CI. VORTEX_CI_TEST_RESULTS=/tmp/tests diff --git a/.vortex/docs/content/development/variables.mdx b/.vortex/docs/content/development/variables.mdx index 49b07f9e0..6355eba1d 100644 --- a/.vortex/docs/content/development/variables.mdx +++ b/.vortex/docs/content/development/variables.mdx @@ -168,6 +168,7 @@ The list below is automatically generated with [Shellvar](https://github.com/ale | `VORTEX_CI_DCLINT_IGNORE_FAILURE` | Ignore DCLint failures. | `UNDEFINED` | `CI config` | | `VORTEX_CI_GHERKIN_LINT_IGNORE_FAILURE` | Ignore Gherkin Lint failures. | `UNDEFINED` | `CI config` | | `VORTEX_CI_HADOLINT_IGNORE_FAILURE` | Ignore Hadolint failures. | `UNDEFINED` | `CI config` | +| `VORTEX_CI_JEST_IGNORE_FAILURE` | Ignore Jest test failures. | `UNDEFINED` | `CI config` | | `VORTEX_CI_NODEJS_LINT_IGNORE_FAILURE` | Ignore NodeJS linters failures. | `UNDEFINED` | `CI config` | | `VORTEX_CI_PHPCS_IGNORE_FAILURE` | Ignore PHPCS failures. | `UNDEFINED` | `CI config` | | `VORTEX_CI_PHPMD_IGNORE_FAILURE` | Ignore PHPMD failures. | `UNDEFINED` | `CI config` | From fb0d46573e7d5bfe4c3436029222254ba06e76b7 Mon Sep 17 00:00:00 2001 From: Alex Skrypnyk Date: Wed, 25 Mar 2026 16:17:14 +1100 Subject: [PATCH 36/36] [#2394] Fixed broken doc links to use /docs/ prefix. --- .vortex/docs/content/development/jest.mdx | 2 +- .vortex/docs/content/tools/jest.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.vortex/docs/content/development/jest.mdx b/.vortex/docs/content/development/jest.mdx index e340005db..caf990892 100644 --- a/.vortex/docs/content/development/jest.mdx +++ b/.vortex/docs/content/development/jest.mdx @@ -10,7 +10,7 @@ testing. Jest tests verify that JavaScript behaviors in custom Drupal modules work correctly in isolation, without requiring a browser or Drupal bootstrap. For running tests, configuration, and CI settings, see the -[Jest tool reference](/tools/jest). +[Jest tool reference](/docs/tools/jest). ## Test file structure diff --git a/.vortex/docs/content/tools/jest.mdx b/.vortex/docs/content/tools/jest.mdx index d18d0f1a6..d47a0c290 100644 --- a/.vortex/docs/content/tools/jest.mdx +++ b/.vortex/docs/content/tools/jest.mdx @@ -11,7 +11,7 @@ https://jestjs.io/ **Vortex** comes with [pre-configured Jest setup](https://github.com/drevops/vortex/blob/main/jest.config.js) for testing JavaScript in custom Drupal modules. For writing tests, mocking Drupal globals, and test templates, see the -[Jest development guide](/development/jest). +[Jest development guide](/docs/development/jest). ## Usage