Configure Vitest for unit and browser tests (use @puppeteer/browsers and webdriverio)

This commit is contained in:
Hugo Alliaume
2025-08-16 19:17:43 +02:00
parent 5eb1153537
commit 01bea6519d
135 changed files with 1954 additions and 457 deletions

5
.gitattributes vendored
View File

@@ -1,5 +0,0 @@
* text=auto eol=lf
/.yarn/** linguist-vendored
/.yarn/releases/* binary
/.yarn/plugins/**/* binary
/.pnp.* binary linguist-generated

43
.github/workflows/browser-tests.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: Browser Tests
defaults:
run:
shell: bash
on:
push:
paths-ignore:
- 'src/*/doc/**'
- 'src/**/*.md'
- 'ux.symfony.com/**'
- '.github/workflows/app-tests.yaml'
- '.github/workflows/unit-tests.yaml'
pull_request:
paths-ignore:
- 'src/*/doc/**'
- 'src/**/*.md'
- 'ux.symfony.com/**'
- '.github/workflows/app-tests.yaml'
- '.github/workflows/unit-tests.yaml'
jobs:
js:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm i -g corepack && corepack enable
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'pnpm'
cache-dependency-path: |
pnpm-lock.yaml
package.json
src/**/package.json
- run: pnpm install --frozen-lockfile
- name: Install browsers
run: node ./bin/get_browsers.mjs
# TODO: Install the E2E app + run webserver
- run: pnpm run test:browser

View File

@@ -1,3 +1,4 @@
# Deprecated, will be removed in favor of browser-tests.yml
name: Functional Tests
defaults:

View File

@@ -143,21 +143,16 @@ jobs:
fi
js:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node-version: [ '18.x', '20.x', '22.x', '24.x' ]
steps:
- uses: actions/checkout@v4
- run: npm i -g corepack && corepack enable
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
node-version-file: '.nvmrc'
cache: 'pnpm'
cache-dependency-path: |
pnpm-lock.yaml
package.json
src/**/package.json
- run: pnpm install --frozen-lockfile
- run: pnpm exec playwright install chromium
- run: pnpm run test
- run: pnpm run test:unit

3
.gitignore vendored
View File

@@ -1,4 +1,3 @@
vendor/
node_modules
.doctor-rst.cache
@@ -7,3 +6,5 @@ node_modules
/composer.lock
/vendor
/browsers

2
.nvmrc
View File

@@ -1 +1 @@
22.11
22.18

View File

@@ -39,7 +39,7 @@ To set up the development environment, you need the following tools:
- [PHP](https://www.php.net/downloads.php) 8.1 or higher
- [Composer](https://getcomposer.org/download/)
- [Node.js](https://nodejs.org/en/download/package-manager) 22.11 or higher
- [Node.js](https://nodejs.org/en/download/package-manager) 22.18 or higher
- [Corepack](https://github.com/nodejs/corepack)
- [PNPM](https://pnpm.io/) 10.13 or higher
@@ -82,12 +82,16 @@ To help you with assets, you can run the following commands in a specific packag
- `pnpm run build`: build (compile) assets from the package,
- `pnpm run watch`: watch for modifications and rebuild assets from the package,
- `pnpm run test`: run the tests from the package,
- `pnpm run test:unit`: run the Unit tests from the package,
- `pnpm run test:browser`: run the Browser tests from the package,
- `pnpm run check`: run the formatter, linter, and sort imports, and fails if any modifications
- `pnpm run check --write`: run the formatter, linter, imports sorting, and write modifications
Thanks to [PNPM Workspaces](https://pnpm.io/workspaces), you can also run these commands from the root directory of the project:
- `pnpm run build`: build (compile) assets from **all** packages,
- `pnpm run test`: run the tests from **all** packages,
- `pnpm run test:unit`: run the Unit tests from **all** packages,
- `pnpm run test:browser`: run the Browser tests from **all** packages,
- `pnpm run check`: run the formatter, linter, and sort imports for **all** packages, and fails if any modifications
- `pnpm run check --write`: run the formatter, linter, imports sorting for **all** packages, and write modifications
@@ -112,7 +116,7 @@ docker run --rm -it -e DOCS_DIR='/docs' -v ${PWD}:/docs oskarstark/doctor-rst -
```shell
$ git checkout 2.x && \
git fetch upstream && \
git rebase upstream/2.x && \
git reset --hard upstream/2.x && \
git push origin 2.x
```

50
bin/get_browsers.mjs Normal file
View File

@@ -0,0 +1,50 @@
import * as path from 'node:path';
import {
Browser,
BrowserTag,
detectBrowserPlatform,
install as installBrowser,
resolveBuildId,
} from '@puppeteer/browsers';
const platform = detectBrowserPlatform();
const installBrowserCommonOpts = {
platform,
cacheDir: path.join(import.meta.dirname, '../browsers'),
downloadProgressCallback: 'default',
};
// Lowest versions are computed from "defaults and fully supports es6-module" query,
// see https://browsersl.ist/#q=defaults+and+fully+supports+es6-module
export const browsers = {
'chrome@lowest': await installBrowser({
...installBrowserCommonOpts,
browser: Browser.CHROME,
// The lowest version where:
// - Chrome and associated Chromedriver could easily be downloaded
// - there is no compatibility issues like "WebDriver Bidi command \"session.subscribe\" failed with error"
// - there is no timeout issues when requesting Vitest webserver
// @see https://raw.githubusercontent.com/GoogleChromeLabs/chrome-for-testing/refs/heads/main/data/known-good-versions-with-downloads.json
buildId: '130.0.6669.0',
}),
'chrome@latest': await installBrowser({
...installBrowserCommonOpts,
browser: Browser.CHROME,
buildId: await resolveBuildId(Browser.CHROME, platform, BrowserTag.STABLE),
}),
'firefox@lowest': await installBrowser({
...installBrowserCommonOpts,
browser: Browser.FIREFOX,
buildId: 'stable_128.0',
}),
'firefox@latest': await installBrowser({
...installBrowserCommonOpts,
browser: Browser.FIREFOX,
buildId: await resolveBuildId(Browser.FIREFOX, platform, BrowserTag.STABLE),
}),
};
if (import.meta.main) {
console.log('Browsers installed:', browsers);
}

View File

@@ -9,10 +9,9 @@ PROJECT_DIR=$(dirname "$SCRIPT_DIR")
# Flag to track if any test fails
all_tests_passed=true
# Check if we have at least one argument
if [ $# -eq 0 ]
then
echo "No arguments supplied, please provide the package's path."
# Check if we have enough arguments
if [ $# -ne 2 ]; then
echo "No arguments supplied, please provide the package's path and the test type (e.g. --unit or --browser)"
fi
# Check if jq is installed
@@ -22,46 +21,58 @@ if ! command -v jq &> /dev/null; then
fi
runTestSuite() {
echo -e "Running tests for $workspace...\n"
pnpm exec vitest --run || { all_tests_passed=false; }
local testProject="$1"
if [ "$testProject" != "unit" ] && [ "$testProject" != "browser" ]; then
echo "Unknown test project: $testProject. Please use 'unit' or 'browser'."
exit 1
fi
echo -e "🧪 Running $testProject tests for $workspace...\n"
pnpm exec vitest --run --config "vitest.config.$testProject.mjs" || { all_tests_passed=false; }
}
processWorkspace() {
local location="$1"
local testProject="$2"
if [ ! -d "$location" ]; then
echo "No directory found at $location"
echo "No directory found at $location"
return
fi
package_json_path="$location/package.json"
if [ ! -f "$package_json_path" ]; then
echo "No package.json found at $package_json_path"
echo "No package.json found at $package_json_path"
return
fi
workspace=$(jq -r '.name' "$package_json_path")
if [ -z "$workspace" ]; then
echo "No name found in package.json at $package_json_path"
echo "No name found in package.json at $package_json_path"
return
fi
echo -e "Processing workspace $workspace at location $location...\n"
echo -e "Processing workspace $workspace at location $location...\n"
echo "Checking '$package_json_path' for peerDependencies and importmap dependencies to have the same version"
echo "⚙️ Checking '$package_json_path' for peerDependencies and importmap dependencies to have the same version"
deps=$(jq -r '.peerDependencies | keys[]' "$package_json_path")
for library in $deps; do
version=$(jq -r ".peerDependencies.\"$library\"" "$package_json_path")
importmap_version=$(jq -r ".symfony.importmap.\"$library\"" "$package_json_path")
importmap_version=$(jq -r ".symfony.importmap.\"$library\" | if type == \"string\" then . else .version end" "$package_json_path")
if [ "$importmap_version" == null ]; then
echo " ⚠ No importmap version found for $library in $package_json_path, skipping..."
continue
fi
if [ "$version" != "$importmap_version" ]; then
echo " -> Version mismatch for $library: $version (peerDependencies) vs $importmap_version (importmap)"
echo " -> You need to match the version of the \"peerDependency\" with the version in the \"importmap\""
exit
echo " Version mismatch for $library: $version (peerDependencies) vs $importmap_version (importmap)"
echo " You need to match the version of the \"peerDependency\" with the version in the \"importmap\""
exit 1
fi
done
echo "Checking '$package_json_path' for peerDependencies with multiple versions defined"
echo "⚙️ Checking '$package_json_path' for peerDependencies with multiple versions defined"
deps_with_multiple_versions=$(jq -r '.peerDependencies | to_entries[] | select(.value | contains("||")) | .key' "$package_json_path")
if [ -n "$deps_with_multiple_versions" ]; then
@@ -78,20 +89,26 @@ processWorkspace() {
echo -e " - Install $library@$trimmed_version for $workspace\n"
pnpm add "$library@$trimmed_version" --save-peer --filter "$workspace"
runTestSuite
runTestSuite "$testProject"
fi
done
done
echo " -> Reverting version changes from $package_json_path"
git checkout -- "$package_json_path"
git checkout -- "$package_json_path" "$PROJECT_DIR/pnpm-lock.yaml"
else
echo -e " -> No peerDependencies found with multiple versions defined\n"
runTestSuite
runTestSuite "$testProject"
fi
}
processWorkspace "$(realpath "$PWD/$1")"
case "$2" in
--unit) testProject="unit" ;;
--browser) testProject="browser" ;;
*) echo "Unknown test type: $2. Please use --unit or --browser."; exit 1 ;;
esac
processWorkspace "$(realpath "$PWD/$1")" "$testProject"
# Check the flag at the end and exit with code 1 if any test failed
if [ "$all_tests_passed" = false ]; then

View File

@@ -5,6 +5,7 @@
"**/*.json",
"**/*.md",
"**/bin/**/*.js",
"**/src/**/assets/*.mjs",
"**/src/**/assets/src/**",
"**/src/**/assets/test/**",
"!**/composer.json",
@@ -12,7 +13,8 @@
"!**/package.json",
"!**/node_modules",
"!**/var",
"!**/dist"
"!**/dist",
"!**/browsers"
]
},
"linter": {

View File

@@ -1,6 +1,6 @@
{
"private": true,
"packageManager": "pnpm@10.13.1+sha512.37ebf1a5c7a30d5fabe0c5df44ee8da4c965ca0c5af3dbab28c3a1681b70a256218d05c81c9c0dcf767ef6b8551eb5b960042b9ed4300c59242336377e01cfad",
"packageManager": "pnpm@10.14.0+sha512.ad27a79641b49c3e481a16a805baa71817a04bbe06a38d17e60e2eaee83f6a146c6a688125f5792e48dd5ba30e7da52a5cda4c3992b9ccf333f9ce223af84748",
"type": "module",
"workspaces": [
"src/*/assets",
@@ -8,21 +8,24 @@
],
"scripts": {
"build": "pnpm run --filter @symfony/ux-map build && pnpm run -r --aggregate-output build",
"test": "pnpm run -r --aggregate-output test",
"test": "pnpm run -r --workspace-concurrency=1 test",
"test:unit": "pnpm run -r --aggregate-output test:unit",
"test:browser": "pnpm run -r --workspace-concurrency=1 test:browser",
"check": "biome check",
"ci": "biome ci"
},
"devDependencies": {
"@biomejs/biome": "^2.0.4",
"@puppeteer/browsers": "^2.10.6",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.6.3",
"@types/node": "^22.6.0",
"lightningcss": "^1.28.2",
"pkg-types": "^2.2.0",
"playwright": "^1.47.0",
"tinyglobby": "^0.2.14",
"tsup": "^8.5.0",
"vitest": "^3.2.4"
"vitest": "^3.2.4",
"webdriverio": "^9.19.1"
},
"version": "2.27.0"
}

1490
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -17,7 +17,9 @@
"scripts": {
"build": "tsx ../../../bin/build_package.ts .",
"watch": "tsx ../../../bin/build_package.ts . --watch",
"test": "../../../bin/test_package.sh .",
"test": "pnpm run test:unit && pnpm run test:browser",
"test:unit": "../../../bin/test_package.sh . --unit",
"test:browser": "../../../bin/test_package.sh . --browser",
"check": "biome check",
"ci": "biome ci"
},

View File

@@ -0,0 +1,7 @@
import { describe, expect, it } from 'vitest';
describe('Placeholder', () => {
it('pass', () => {
expect(true).toBe(true);
});
});

View File

@@ -16,7 +16,7 @@ import createFetchMock from 'vitest-fetch-mock';
import AutocompleteController, {
type AutocompleteConnectOptions,
type AutocompletePreConnectOptions,
} from '../src/controller';
} from '../../src/controller';
const shortDelay = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));

View File

@@ -0,0 +1,4 @@
import { mergeConfig } from 'vitest/config';
import configShared from '../../../vitest.config.browser.mjs';
export default mergeConfig(configShared, {});

View File

@@ -0,0 +1,4 @@
import { mergeConfig } from 'vitest/config';
import configShared from '../../../vitest.config.unit.mjs';
export default mergeConfig(configShared, {});

View File

@@ -17,7 +17,9 @@
"scripts": {
"build": "tsx ../../../bin/build_package.ts .",
"watch": "tsx ../../../bin/build_package.ts . --watch",
"test": "../../../bin/test_package.sh .",
"test": "pnpm run test:unit && pnpm run test:browser",
"test:unit": "../../../bin/test_package.sh . --unit",
"test:browser": "../../../bin/test_package.sh . --browser",
"check": "biome check",
"ci": "biome ci"
},

View File

@@ -0,0 +1,7 @@
import { describe, expect, it } from 'vitest';
describe('Placeholder', () => {
it('pass', () => {
expect(true).toBe(true);
});
});

View File

@@ -10,7 +10,7 @@
import { Application } from '@hotwired/stimulus';
import { waitFor } from '@testing-library/dom';
import { afterEach, beforeAll, describe, expect, it } from 'vitest';
import ChartjsController from '../src/controller';
import ChartjsController from '../../src/controller';
// Kept track of globally, but just used in one test.
// This is because, by the time that test has run, it is likely that the

View File

@@ -0,0 +1,4 @@
import { mergeConfig } from 'vitest/config';
import configShared from '../../../vitest.config.browser.mjs';
export default mergeConfig(configShared, {});

View File

@@ -1,19 +0,0 @@
import { defineConfig, mergeConfig } from 'vitest/config';
import configShared from '../../../vitest.config.mjs'
import path from 'path';
export default mergeConfig(
configShared,
defineConfig({
test: {
setupFiles: [path.join(__dirname, 'test', 'setup.js')],
deps: {
optimizer: {
web: {
include: ['vitest-canvas-mock'],
},
},
},
}
})
);

View File

@@ -0,0 +1,16 @@
import path from 'node:path';
import { mergeConfig } from 'vitest/config';
import configShared from '../../../vitest.config.unit.mjs';
export default mergeConfig(configShared, {
test: {
setupFiles: [path.join(__dirname, 'test', 'setup.js')],
deps: {
optimizer: {
web: {
include: ['vitest-canvas-mock'],
},
},
},
},
});

View File

@@ -20,7 +20,9 @@
"scripts": {
"build": "tsx ../../../bin/build_package.ts .",
"watch": "tsx ../../../bin/build_package.ts . --watch",
"test": "../../../bin/test_package.sh .",
"test": "pnpm run test:unit && pnpm run test:browser",
"test:unit": "../../../bin/test_package.sh . --unit",
"test:browser": "../../../bin/test_package.sh . --browser",
"check": "biome check",
"ci": "biome ci"
},

View File

@@ -0,0 +1,7 @@
import { describe, expect, it } from 'vitest';
describe('Placeholder', () => {
it('pass', () => {
expect(true).toBe(true);
});
});

View File

@@ -10,8 +10,8 @@
import { Application, Controller } from '@hotwired/stimulus';
import { getByTestId, waitFor } from '@testing-library/dom';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { clearDOM, mountDOM } from '../../../../test/stimulus-helpers';
import CropperjsController from '../src/controller';
import { clearDOM, mountDOM } from '../../../../../test/stimulus-helpers';
import CropperjsController from '../../src/controller';
let cropper: Cropper | null = null;

View File

@@ -0,0 +1,4 @@
import { mergeConfig } from 'vitest/config';
import configShared from '../../../vitest.config.browser.mjs';
export default mergeConfig(configShared, {});

View File

@@ -0,0 +1,4 @@
import { mergeConfig } from 'vitest/config';
import configShared from '../../../vitest.config.unit.mjs';
export default mergeConfig(configShared, {});

View File

@@ -20,7 +20,9 @@
"scripts": {
"build": "tsx ../../../bin/build_package.ts .",
"watch": "tsx ../../../bin/build_package.ts . --watch",
"test": "../../../bin/test_package.sh .",
"test": "pnpm run test:unit && pnpm run test:browser",
"test:unit": "../../../bin/test_package.sh . --unit",
"test:browser": "../../../bin/test_package.sh . --browser",
"check": "biome check",
"ci": "biome ci"
},

View File

@@ -0,0 +1,7 @@
import { describe, expect, it } from 'vitest';
describe('Placeholder', () => {
it('pass', () => {
expect(true).toBe(true);
});
});

View File

@@ -11,8 +11,8 @@ import { Application, Controller } from '@hotwired/stimulus';
import { getByTestId, waitFor } from '@testing-library/dom';
import user from '@testing-library/user-event';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { clearDOM, mountDOM } from '../../../../test/stimulus-helpers';
import DropzoneController from '../src/controller';
import { clearDOM, mountDOM } from '../../../../../test/stimulus-helpers';
import DropzoneController from '../../src/controller';
// Controller used to check the actual controller was properly booted
class CheckController extends Controller {

View File

@@ -0,0 +1,4 @@
import { mergeConfig } from 'vitest/config';
import configShared from '../../../vitest.config.browser.mjs';
export default mergeConfig(configShared, {});

View File

@@ -0,0 +1,4 @@
import { mergeConfig } from 'vitest/config';
import configShared from '../../../vitest.config.unit.mjs';
export default mergeConfig(configShared, {});

View File

@@ -17,7 +17,8 @@
"scripts": {
"build": "tsx ../../../bin/build_package.ts .",
"watch": "tsx ../../../bin/build_package.ts . --watch",
"test": "../../../bin/test_package.sh .",
"test": "pnpm run test:unit",
"test:unit": "../../../bin/test_package.sh . --unit",
"check": "biome check",
"ci": "biome ci"
},

View File

@@ -10,8 +10,8 @@
import { Application, Controller } from '@hotwired/stimulus';
import { getByTestId, waitFor } from '@testing-library/dom';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { clearDOM, mountDOM } from '../../../../test/stimulus-helpers';
import LazyImageController from '../src/controller';
import { clearDOM, mountDOM } from '../../../../../test/stimulus-helpers';
import LazyImageController from '../../src/controller';
// Controller used to check the actual controller was properly booted
class CheckController extends Controller {

View File

@@ -0,0 +1,4 @@
import { mergeConfig } from 'vitest/config';
import configShared from '../../../vitest.config.unit.mjs';
export default mergeConfig(configShared, {});

View File

@@ -22,7 +22,9 @@
"scripts": {
"build": "tsx ../../../bin/build_package.ts .",
"watch": "tsx ../../../bin/build_package.ts . --watch",
"test": "../../../bin/test_package.sh .",
"test": "pnpm run test:unit && pnpm run test:browser",
"test:unit": "../../../bin/test_package.sh . --unit",
"test:browser": "../../../bin/test_package.sh . --browser",
"check": "biome check",
"ci": "biome ci"
},
@@ -49,10 +51,10 @@
},
"devDependencies": {
"@hotwired/stimulus": "^3.0.0",
"@testing-library/dom": "^7.31.0",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/user-event": "^13.1.9",
"@types/node-fetch": "^2.6.2",
"@types/node-fetch": "^2.6.13",
"idiomorph": "^0.3.0",
"jsdom": "^26.1.0",
"node-fetch": "^2.6.1",

View File

@@ -0,0 +1,7 @@
import { describe, expect, it } from 'vitest';
describe('Placeholder', () => {
it('pass', () => {
expect(true).toBe(true);
});
});

View File

@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest';
import RequestBuilder from '../../src/Backend/RequestBuilder';
import RequestBuilder from '../../../src/Backend/RequestBuilder';
describe('buildRequest', () => {
it('sets basic data on GET request', () => {

View File

@@ -1,11 +1,11 @@
import { waitFor } from '@testing-library/dom';
import { Response } from 'node-fetch';
import { describe, expect, it } from 'vitest';
import type { BackendAction, BackendInterface } from '../../src/Backend/Backend';
import BackendRequest from '../../src/Backend/BackendRequest';
import type BackendResponse from '../../src/Backend/BackendResponse';
import Component, { proxifyComponent } from '../../src/Component';
import { noopElementDriver } from '../tools';
import type { BackendAction, BackendInterface } from '../../../src/Backend/Backend';
import BackendRequest from '../../../src/Backend/BackendRequest';
import type BackendResponse from '../../../src/Backend/BackendResponse';
import Component, { proxifyComponent } from '../../../src/Component';
import { noopElementDriver } from '../../tools';
interface MockBackend extends BackendInterface {
actions: BackendAction[];

View File

@@ -1,10 +1,10 @@
import { Response } from 'node-fetch';
import { beforeEach, describe, expect, it } from 'vitest';
import type { BackendInterface } from '../src/Backend/Backend';
import BackendRequest from '../src/Backend/BackendRequest';
import Component from '../src/Component';
import { findComponents, getComponent, registerComponent, resetRegistry } from '../src/ComponentRegistry';
import { noopElementDriver } from './tools';
import type { BackendInterface } from '../../src/Backend/Backend';
import BackendRequest from '../../src/Backend/BackendRequest';
import Component from '../../src/Component';
import { findComponents, getComponent, registerComponent, resetRegistry } from '../../src/ComponentRegistry';
import { noopElementDriver } from '../tools';
const createComponent = (element: HTMLElement, name = 'foo-component'): Component => {
const backend: BackendInterface = {

View File

@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest';
import { type Directive, parseDirectives } from '../../src/Directive/directives_parser';
import { type Directive, parseDirectives } from '../../../src/Directive/directives_parser';
const assertDirectiveEquals = (actual: Directive, expected: any) => {
// normalize this so that it doesn't trip up the comparison

View File

@@ -1,6 +1,6 @@
import { describe, expect, it } from 'vitest';
import { parseDirectives } from '../../src/Directive/directives_parser';
import getModelBinding from '../../src/Directive/get_model_binding';
import { parseDirectives } from '../../../src/Directive/directives_parser';
import getModelBinding from '../../../src/Directive/get_model_binding';
describe('get_model_binding', () => {
it('returns correctly with simple directive', () => {

View File

@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest';
import ChangingItemsTracker from '../../src/Rendering/ChangingItemsTracker';
import ChangingItemsTracker from '../../../src/Rendering/ChangingItemsTracker';
describe('ChangingItemsTracker', () => {
it('tracks style change red -> blue -> green', async () => {

View File

@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest';
import ElementChanges from '../../src/Rendering/ElementChanges';
import ElementChanges from '../../../src/Rendering/ElementChanges';
describe('ElementChanges', () => {
it('tracks class additions and removals', async () => {

View File

@@ -1,6 +1,6 @@
import { describe, expect, it } from 'vitest';
import { htmlToElement } from '../../src/dom_utils';
import ExternalMutationTracker from '../../src/Rendering/ExternalMutationTracker';
import { htmlToElement } from '../../../src/dom_utils';
import ExternalMutationTracker from '../../../src/Rendering/ExternalMutationTracker';
const mountElement = (html: string): HTMLElement => {
const element = htmlToElement(html);

View File

@@ -1,6 +1,6 @@
import { describe, expect, it } from 'vitest';
import { UnsyncedInputContainer } from '../src/Component/UnsyncedInputsTracker';
import { htmlToElement } from '../src/dom_utils';
import { UnsyncedInputContainer } from '../../src/Component/UnsyncedInputsTracker';
import { htmlToElement } from '../../src/dom_utils';
describe('UnsyncedInputContainer', () => {
it('returns items added to it', () => {

View File

@@ -1,6 +1,6 @@
import { describe, expect, it } from 'vitest';
import { htmlToElement } from '../../src/dom_utils';
import getElementAsTagText from '../../src/Util/getElementAsTagText';
import { htmlToElement } from '../../../src/dom_utils';
import getElementAsTagText from '../../../src/Util/getElementAsTagText';
describe('getElementAsTagText', () => {
it('returns self-closing tag correctly', () => {

View File

@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest';
import ValueStore from '../src/Component/ValueStore';
import ValueStore from '../../src/Component/ValueStore';
describe('ValueStore', () => {
const getDataset = [

View File

@@ -10,7 +10,7 @@
import { getByText, waitFor } from '@testing-library/dom';
import userEvent from '@testing-library/user-event';
import { afterEach, describe, expect, it } from 'vitest';
import { createTest, initComponent, shutdownTests } from '../tools';
import { createTest, initComponent, shutdownTests } from '../../tools';
describe('LiveController Action Tests', () => {
afterEach(() => {

View File

@@ -8,11 +8,11 @@
*/
import { afterEach, describe, expect, it } from 'vitest';
import Component from '../../src/Component';
import { findComponents } from '../../src/ComponentRegistry';
import { htmlToElement } from '../../src/dom_utils';
import { getComponent } from '../../src/live_controller';
import { createTest, initComponent, shutdownTests, startStimulus } from '../tools';
import Component from '../../../src/Component';
import { findComponents } from '../../../src/ComponentRegistry';
import { htmlToElement } from '../../../src/dom_utils';
import { getComponent } from '../../../src/live_controller';
import { createTest, initComponent, shutdownTests, startStimulus } from '../../tools';
describe('LiveController Basic Tests', () => {
afterEach(() => {

View File

@@ -10,7 +10,7 @@
import { getByTestId, waitFor } from '@testing-library/dom';
import userEvent from '@testing-library/user-event';
import { afterEach, describe, expect, it } from 'vitest';
import { createTest, initComponent, shutdownTests } from '../tools';
import { createTest, initComponent, shutdownTests } from '../../tools';
describe('Component parent -> child data-model binding tests', () => {
afterEach(() => {

View File

@@ -11,7 +11,7 @@ import { Controller } from '@hotwired/stimulus';
import { getByTestId, waitFor } from '@testing-library/dom';
import userEvent from '@testing-library/user-event';
import { afterEach, describe, expect, it } from 'vitest';
import { findChildren } from '../../src/ComponentRegistry';
import { findChildren } from '../../../src/ComponentRegistry';
import {
createTest,
createTestForExistingComponent,
@@ -20,7 +20,7 @@ import {
getStimulusApplication,
initComponent,
shutdownTests,
} from '../tools';
} from '../../tools';
describe('Component parent -> child initialization and rendering tests', () => {
afterEach(() => {

View File

@@ -8,7 +8,7 @@
*/
import { afterEach, describe, expect, it } from 'vitest';
import { createTest, initComponent, shutdownTests } from '../tools';
import { createTest, initComponent, shutdownTests } from '../../tools';
describe('LiveController Event Dispatching Tests', () => {
afterEach(() => {

View File

@@ -9,7 +9,7 @@
import { getByText, waitFor } from '@testing-library/dom';
import { afterEach, describe, expect, it } from 'vitest';
import { createTest, initComponent, shutdownTests } from '../tools';
import { createTest, initComponent, shutdownTests } from '../../tools';
describe('LiveController Emit Tests', () => {
afterEach(() => {

View File

@@ -9,8 +9,8 @@
import { getByText, waitFor } from '@testing-library/dom';
import { afterEach, describe, expect, it } from 'vitest';
import type BackendResponse from '../../src/Backend/BackendResponse';
import { createTest, initComponent, shutdownTests } from '../tools';
import type BackendResponse from '../../../src/Backend/BackendResponse';
import { createTest, initComponent, shutdownTests } from '../../tools';
const getErrorElement = (): Element | null => {
return document.getElementById('live-component-error');

View File

@@ -10,7 +10,7 @@
import { getByTestId, getByText, waitFor } from '@testing-library/dom';
import userEvent from '@testing-library/user-event';
import { afterEach, describe, expect, it } from 'vitest';
import { createTest, initComponent, shutdownTests } from '../tools';
import { createTest, initComponent, shutdownTests } from '../../tools';
describe('LiveController data-loading Tests', () => {
afterEach(() => {
@@ -167,7 +167,7 @@ describe('LiveController data-loading Tests', () => {
// delay so we can check loading
.delayResponse(50);
userEvent.type(test.queryByDataModel('user.email'), 'ryan@symfonycasts.com');
await userEvent.type(test.queryByDataModel('user.email'), 'ryan@symfonycasts.com');
// it should not be loading yet due to debouncing
expect(getByTestId(test.element, 'email-loading')).not.toBeVisible();
// wait for ajax call to start

View File

@@ -10,7 +10,7 @@
import { getByLabelText, getByTestId, getByText, waitFor } from '@testing-library/dom';
import userEvent from '@testing-library/user-event';
import { afterEach, describe, expect, it } from 'vitest';
import { createTest, initComponent, shutdownTests } from '../tools';
import { createTest, initComponent, shutdownTests } from '../../tools';
describe('LiveController data-model Tests', () => {
afterEach(() => {
@@ -835,7 +835,7 @@ describe('LiveController data-model Tests', () => {
commentField.dispatchEvent(new Event('input', { bubbles: true }));
// also type into the unmapped field - but no worry about the model sync'ing this time
userEvent.type(getByTestId(test.element, 'unmappedTextarea'), ' here!');
await userEvent.type(getByTestId(test.element, 'unmappedTextarea'), ' here!');
await waitFor(() => expect(test.element).toHaveTextContent('FieldClass: changed-class'));
// re-find in case the element itself has changed by morphdom

View File

@@ -10,7 +10,7 @@
import { waitFor } from '@testing-library/dom';
import userEvent from '@testing-library/user-event';
import { afterEach, describe, expect, it } from 'vitest';
import { createTest, initComponent, shutdownTests } from '../tools';
import { createTest, initComponent, shutdownTests } from '../../tools';
describe('LiveController polling Tests', () => {
afterEach(() => {

View File

@@ -9,7 +9,7 @@
import { getByText, waitFor } from '@testing-library/dom';
import { afterEach, describe, expect, it } from 'vitest';
import { createTest, expectCurrentSearch, initComponent, setCurrentSearch, shutdownTests } from '../tools';
import { createTest, expectCurrentSearch, initComponent, setCurrentSearch, shutdownTests } from '../../tools';
describe('LiveController query string binding', () => {
afterEach(() => {

View File

@@ -9,8 +9,8 @@
import { getByTestId } from '@testing-library/dom';
import { afterEach, describe, expect, it } from 'vitest';
import { htmlToElement } from '../../src/dom_utils';
import { createTest, initComponent, shutdownTests } from '../tools';
import { htmlToElement } from '../../../src/dom_utils';
import { createTest, initComponent, shutdownTests } from '../../tools';
describe('LiveController rendering with external changes tests', () => {
afterEach(() => {

View File

@@ -10,8 +10,8 @@
import { getByTestId, getByText, waitFor } from '@testing-library/dom';
import userEvent from '@testing-library/user-event';
import { afterEach, describe, expect, it } from 'vitest';
import { htmlToElement } from '../../src/dom_utils';
import { createTest, initComponent, shutdownTests } from '../tools';
import { htmlToElement } from '../../../src/dom_utils';
import { createTest, initComponent, shutdownTests } from '../../tools';
describe('LiveController rendering Tests', () => {
afterEach(() => {

View File

@@ -1,7 +1,7 @@
import { describe, expect, it } from 'vitest';
import Backend from '../src/Backend/Backend';
import Component from '../src/Component';
import ValueStore from '../src/Component/ValueStore';
import Backend from '../../src/Backend/Backend';
import Component from '../../src/Component';
import ValueStore from '../../src/Component/ValueStore';
import {
cloneHTMLElement,
elementBelongsToThisComponent,
@@ -12,8 +12,8 @@ import {
isTextareaElement,
isTextualInputElement,
setValueOnElement,
} from '../src/dom_utils';
import { noopElementDriver } from './tools';
} from '../../src/dom_utils';
import { noopElementDriver } from '../tools';
const createStore = (props: any = {}): ValueStore => new ValueStore(props);

View File

@@ -1,6 +1,6 @@
import { describe, expect, it } from 'vitest';
import { htmlToElement } from '../src/dom_utils';
import { normalizeAttributesForComparison } from '../src/normalize_attributes_for_comparison';
import { htmlToElement } from '../../src/dom_utils';
import { normalizeAttributesForComparison } from '../../src/normalize_attributes_for_comparison';
describe('normalizeAttributesForComparison', () => {
it('makes no changes if value and attribute not set', () => {

View File

@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest';
import { combineSpacedArray, normalizeModelName } from '../src/string_utils';
import { combineSpacedArray, normalizeModelName } from '../../src/string_utils';
describe('combinedSpacedArray', () => {
it('parse normal array', () => {

View File

@@ -0,0 +1,4 @@
import { mergeConfig } from 'vitest/config';
import configShared from '../../../vitest.config.browser.mjs';
export default mergeConfig(configShared, {});

View File

@@ -0,0 +1,4 @@
import { mergeConfig } from 'vitest/config';
import configShared from '../../../vitest.config.unit.mjs';
export default mergeConfig(configShared, {});

View File

@@ -21,7 +21,8 @@
"scripts": {
"build": "tsx ../../../bin/build_package.ts .",
"watch": "tsx ../../../bin/build_package.ts . --watch",
"test": "../../../bin/test_package.sh .",
"test": "pnpm run test:unit",
"test:unit": "../../../bin/test_package.sh . --unit",
"check": "biome check",
"ci": "biome ci"
},

View File

@@ -1,8 +1,8 @@
import { Application } from '@hotwired/stimulus';
import { getByTestId, waitFor } from '@testing-library/dom';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { clearDOM, mountDOM } from '../../../../test/stimulus-helpers';
import AbstractMapController from '../src/abstract_map_controller.ts';
import { clearDOM, mountDOM } from '../../../../../test/stimulus-helpers';
import AbstractMapController from '../../src/abstract_map_controller.ts';
class MyMapController extends AbstractMapController {
protected dispatchEvent(name: string, payload: Record<string, unknown> = {}): void {

View File

@@ -0,0 +1,4 @@
import { mergeConfig } from 'vitest/config';
import configShared from '../../../vitest.config.unit.mjs';
export default mergeConfig(configShared, {});

View File

@@ -19,7 +19,8 @@
"scripts": {
"build": "tsx ../../../../../../bin/build_package.ts .",
"watch": "tsx ../../../../../../bin/build_package.ts . --watch",
"test": "../../../../../../bin/test_package.sh .",
"test": "pnpm run test:browser",
"test:browser": "../../../../../../bin/test_package.sh . --browser",
"check": "biome check",
"ci": "biome ci"
},

View File

@@ -10,8 +10,8 @@
import { Application, Controller } from '@hotwired/stimulus';
import { getByTestId, waitFor } from '@testing-library/dom';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { clearDOM, mountDOM } from '../../../../../../../test/stimulus-helpers';
import GoogleController from '../src/map_controller';
import { clearDOM, mountDOM } from '../../../../../../../../test/stimulus-helpers';
import GoogleController from '../../src/map_controller';
// Controller used to check the actual controller was properly booted
class CheckController extends Controller {

View File

@@ -0,0 +1,10 @@
import { mergeConfig } from 'vitest/config';
import configShared from '../../../../../../vitest.config.browser.mjs';
export default mergeConfig(configShared, {
resolve: {
alias: {
'@symfony/ux-map': __dirname + '/../../../../assets/src/abstract_map_controller.ts',
},
},
});

View File

@@ -1,29 +0,0 @@
import { defineConfig, mergeConfig } from 'vitest/config';
import configShared from '../../../../../../vitest.config.mjs'
export default mergeConfig(
configShared,
defineConfig({
resolve: {
alias: {
'@symfony/ux-map': __dirname + '/../../../../assets/src/abstract_map_controller.ts',
},
},
define: {
// Prevent the following error:
// ReferenceError: global is not defined
// ../../../../../../node_modules/pretty-format/build/plugins/AsymmetricMatcher.js ../../../../../../../../../../node_modules/.vite/deps/@testing-library_dom.js:139:19
// ../../../../../../node_modules/pretty-format/build/index.js ../../../../../../../../../../node_modules/.vite/deps/@testing-library_dom.js:805:7
// ../../../../../../../../../../node_modules/.vite/deps/@testing-library_dom.js:13445:36
global: {}
},
test: {
browser: {
enabled: true,
provider: 'playwright', // or 'webdriverio'
instances: [{ browser: 'chromium' }],
headless: true,
},
},
})
);

View File

@@ -19,7 +19,8 @@
"scripts": {
"build": "tsx ../../../../../../bin/build_package.ts .",
"watch": "tsx ../../../../../../bin/build_package.ts . --watch",
"test": "../../../../../../bin/test_package.sh .",
"test": "pnpm run test:browser",
"test:browser": "../../../../../../bin/test_package.sh . --browser",
"check": "biome check",
"ci": "biome ci"
},

View File

@@ -10,8 +10,8 @@
import { Application, Controller } from '@hotwired/stimulus';
import { getByTestId, waitFor } from '@testing-library/dom';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { clearDOM, mountDOM } from '../../../../../../../test/stimulus-helpers';
import LeafletController from '../src/map_controller';
import { clearDOM, mountDOM } from '../../../../../../../../test/stimulus-helpers';
import LeafletController from '../../src/map_controller';
// Controller used to check the actual controller was properly booted
class CheckController extends Controller {

View File

@@ -0,0 +1,11 @@
import { mergeConfig } from 'vitest/config';
import configShared from '../../../../../../vitest.config.browser.mjs';
export default mergeConfig(configShared, {
resolve: {
alias: {
'@symfony/ux-map': __dirname + '/../../../../assets/src/abstract_map_controller.ts',
'leaflet/dist/leaflet.min.css': 'leaflet/dist/leaflet.css',
},
},
});

View File

@@ -1,30 +0,0 @@
import { defineConfig, mergeConfig } from 'vitest/config';
import configShared from '../../../../../../vitest.config.mjs'
export default mergeConfig(
configShared,
defineConfig({
resolve: {
alias: {
'@symfony/ux-map': __dirname + '/../../../../assets/src/abstract_map_controller.ts',
'leaflet/dist/leaflet.min.css': 'leaflet/dist/leaflet.css',
},
},
define: {
// Prevent the following error:
// ReferenceError: global is not defined
// ../../../../../../node_modules/pretty-format/build/plugins/AsymmetricMatcher.js ../../../../../../../../../../node_modules/.vite/deps/@testing-library_dom.js:139:19
// ../../../../../../node_modules/pretty-format/build/index.js ../../../../../../../../../../node_modules/.vite/deps/@testing-library_dom.js:805:7
// ../../../../../../../../../../node_modules/.vite/deps/@testing-library_dom.js:13445:36
global: {}
},
test: {
browser: {
enabled: true,
provider: 'playwright', // or 'webdriverio'
instances: [{ browser: 'chromium' }],
headless: true,
},
},
})
);

View File

@@ -17,7 +17,9 @@
"scripts": {
"build": "tsx ../../../bin/build_package.ts .",
"watch": "tsx ../../../bin/build_package.ts . --watch",
"test": "../../../bin/test_package.sh .",
"test": "pnpm run test:unit && pnpm run test:browser",
"test:unit": "../../../bin/test_package.sh . --unit",
"test:browser": "../../../bin/test_package.sh . --browser",
"check": "biome check",
"ci": "biome ci"
},

View File

@@ -0,0 +1,7 @@
import { describe, expect, it } from 'vitest';
describe('Placeholder', () => {
it('pass', () => {
expect(true).toBe(true);
});
});

View File

@@ -10,8 +10,8 @@
import { Application, Controller } from '@hotwired/stimulus';
import { getByTestId, waitFor } from '@testing-library/dom';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { clearDOM, mountDOM } from '../../../../test/stimulus-helpers';
import NotifyController from '../src/controller';
import { clearDOM, mountDOM } from '../../../../../test/stimulus-helpers';
import NotifyController from '../../src/controller';
// Controller used to check the actual controller was properly booted
class CheckController extends Controller {

View File

@@ -0,0 +1,4 @@
import { mergeConfig } from 'vitest/config';
import configShared from '../../../vitest.config.browser.mjs';
export default mergeConfig(configShared, {});

View File

@@ -0,0 +1,4 @@
import { mergeConfig } from 'vitest/config';
import configShared from '../../../vitest.config.unit.mjs';
export default mergeConfig(configShared, {});

View File

@@ -17,7 +17,9 @@
"scripts": {
"build": "tsx ../../../bin/build_package.ts .",
"watch": "tsx ../../../bin/build_package.ts . --watch",
"test": "../../../bin/test_package.sh .",
"test": "pnpm run test:unit && pnpm run test:browser",
"test:unit": "../../../bin/test_package.sh . --unit",
"test:browser": "../../../bin/test_package.sh . --browser",
"check": "biome check",
"ci": "biome ci"
},

View File

@@ -0,0 +1,7 @@
import { describe, expect, it } from 'vitest';
describe('Placeholder', () => {
it('pass', () => {
expect(true).toBe(true);
});
});

View File

@@ -8,10 +8,10 @@
*/
import { describe, expect, it } from 'vitest';
import { registerReactControllerComponents } from '../src/register_controller';
import { registerReactControllerComponents } from '../../src/register_controller';
// @ts-ignore
import MyJsxComponent from './fixtures/MyJsxComponent';
import MyTsxComponent from './fixtures/MyTsxComponent';
import MyJsxComponent from '../fixtures/MyJsxComponent';
import MyTsxComponent from '../fixtures/MyTsxComponent';
import RequireContext = __WebpackModuleApi.RequireContext;

View File

@@ -10,8 +10,8 @@
import { Application, Controller } from '@hotwired/stimulus';
import { getByTestId, waitFor } from '@testing-library/dom';
import { describe, expect, it } from 'vitest';
import { clearDOM, mountDOM } from '../../../../test/stimulus-helpers';
import ReactController from '../src/render_controller';
import { clearDOM, mountDOM } from '../../../../../test/stimulus-helpers';
import ReactController from '../../src/render_controller';
// Controller used to check the actual controller was properly booted
class CheckController extends Controller {

View File

@@ -0,0 +1,4 @@
import { mergeConfig } from 'vitest/config';
import configShared from '../../../vitest.config.browser.mjs';
export default mergeConfig(configShared, {});

View File

@@ -1,11 +0,0 @@
// vitest.config.ts
import { defineConfig, mergeConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
import configShared from '../../../vitest.config.mjs'
export default mergeConfig(
configShared,
defineConfig({
plugins: [react()],
})
);

View File

@@ -0,0 +1,7 @@
import react from '@vitejs/plugin-react';
import { mergeConfig } from 'vitest/config';
import configShared from '../../../vitest.config.unit.mjs';
export default mergeConfig(configShared, {
plugins: [react()],
});

View File

@@ -17,7 +17,8 @@
"scripts": {
"build": "tsx ../../../bin/build_package.ts .",
"watch": "tsx ../../../bin/build_package.ts . --watch",
"test": "../../../bin/test_package.sh .",
"test": "pnpm run test:unit && pnpm run test:browser",
"test:unit": "../../../bin/test_package.sh . --unit",
"check": "biome check",
"ci": "biome ci"
},

View File

@@ -3,8 +3,8 @@ import { waitFor } from '@testing-library/dom';
import { describe, expect, it } from 'vitest';
// load from dist because the source TypeScript file points directly to controllers.js,
// which does not actually exist in the source code
import { loadControllers } from '../dist/loader';
import type { EagerControllersCollection, LazyControllersCollection } from '../src/controllers';
import { loadControllers } from '../../dist/loader';
import type { EagerControllersCollection, LazyControllersCollection } from '../../src/controllers';
let isController1Initialized = false;
let isController2Initialized = false;

View File

@@ -0,0 +1,4 @@
import { mergeConfig } from 'vitest/config';
import configShared from '../../../vitest.config.unit.mjs';
export default mergeConfig(configShared, {});

View File

@@ -16,7 +16,9 @@
"scripts": {
"build": "tsx ../../../bin/build_package.ts .",
"watch": "tsx ../../../bin/build_package.ts . --watch",
"test": "../../../bin/test_package.sh .",
"test": "pnpm run test:unit && pnpm run test:browser",
"test:unit": "../../../bin/test_package.sh . --unit",
"test:browser": "../../../bin/test_package.sh . --browser",
"check": "biome check",
"ci": "biome ci"
},

View File

@@ -0,0 +1,7 @@
import { describe, expect, it } from 'vitest';
describe('Placeholder', () => {
it('pass', () => {
expect(true).toBe(true);
});
});

View File

@@ -8,8 +8,8 @@
*/
import { describe, expect, it } from 'vitest';
import { registerSvelteControllerComponents } from '../src/register_controller';
import MyComponent from './fixtures/MyComponent.svelte';
import { registerSvelteControllerComponents } from '../../src/register_controller';
import MyComponent from '../fixtures/MyComponent.svelte';
import RequireContext = __WebpackModuleApi.RequireContext;

View File

@@ -10,9 +10,9 @@
import { Application, Controller } from '@hotwired/stimulus';
import { getByTestId, waitFor } from '@testing-library/dom';
import { afterEach, describe, expect, it } from 'vitest';
import { clearDOM, mountDOM } from '../../../../test/stimulus-helpers';
import SvelteController from '../src/render_controller';
import MyComponent from './fixtures/MyComponent.svelte';
import { clearDOM, mountDOM } from '../../../../../test/stimulus-helpers';
import SvelteController from '../../src/render_controller';
import MyComponent from '../fixtures/MyComponent.svelte';
// Controller used to check the actual controller was properly booted
class CheckController extends Controller {

View File

@@ -0,0 +1,4 @@
import { mergeConfig } from 'vitest/config';
import configShared from '../../../vitest.config.browser.mjs';
export default mergeConfig(configShared, {});

View File

@@ -1,11 +0,0 @@
// vitest.config.ts
import { defineConfig, mergeConfig } from 'vitest/config';
import { svelte } from '@sveltejs/vite-plugin-svelte';
import configShared from '../../../vitest.config.mjs'
export default mergeConfig(
configShared,
defineConfig({
plugins: [svelte()],
})
);

View File

@@ -0,0 +1,7 @@
import { svelte } from '@sveltejs/vite-plugin-svelte';
import { mergeConfig } from 'vitest/config';
import configShared from '../../../vitest.config.unit.mjs';
export default mergeConfig(configShared, {
plugins: [svelte()],
});

Some files were not shown because too many files have changed in this diff Show More