diff --git a/packages/web-forms/vite.config.ts b/packages/web-forms/vite.config.ts index cac966afa..6f84bcc92 100644 --- a/packages/web-forms/vite.config.ts +++ b/packages/web-forms/vite.config.ts @@ -1,34 +1,101 @@ +import { CollectionValues } from '@getodk/common/types/collections/CollectionValues'; import vue from '@vitejs/plugin-vue'; import vueJsx from '@vitejs/plugin-vue-jsx'; +import { existsSync } from 'node:fs'; +import { resolve } from 'node:path'; import { fileURLToPath, URL } from 'node:url'; -import { resolve } from 'path'; import unpluginFonts from 'unplugin-fonts/vite'; -import { defineConfig, UserConfig } from 'vite'; +import type { LibraryOptions } from 'vite'; import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'; +import { defineConfig } from 'vitest/config'; -const bundleFonts = () => - unpluginFonts({ - fontsource: { - families: [ - { - /** - * Name of the font family. - * Require the `@fontsource/roboto` package to be installed. - */ - name: 'Roboto', - /** - * Load only a subset of the font family. - */ - weights: [300], - }, - ], - }, - }); +const supportedBrowsers = new Set(['chromium', 'firefox', 'webkit'] as const); + +type SupportedBrowser = CollectionValues; + +const isSupportedBrowser = (browserName: string): browserName is SupportedBrowser => + supportedBrowsers.has(browserName as SupportedBrowser); + +const BROWSER_NAME = (() => { + const envBrowserName = process.env.BROWSER_NAME; + + if (envBrowserName == null) { + return null; + } + + if (isSupportedBrowser(envBrowserName)) { + return envBrowserName; + } + + throw new Error(`Unsupported browser: ${envBrowserName}`); +})(); + +const BROWSER_ENABLED = BROWSER_NAME != null; + +const TEST_ENVIRONMENT = BROWSER_ENABLED ? 'node' : 'jsdom'; + +const globalSetup: string[] = []; -export default defineConfig((env) => { - const config: UserConfig = { +/** + * @todo this is (hopefully!) temporary. Adds a delay when testing in + * `webkit`, to help mitigate flakiness that seems to be rooted in + * first-run timing issues (where "first" = "no Vite cache"; the issue was + * much more consistently reproducible in a state where + * `node_modules/.vite` is not present). + */ +const webkitFlakinessMitigations = + BROWSER_NAME === 'webkit' && !existsSync('./node_modules/.vite/deps'); + +if (webkitFlakinessMitigations) { + globalSetup.push('./tests/globalSetup/mitigate-webkit-flakiness.ts'); +} + +export default defineConfig(({ mode }) => { + const isVueBundled = mode === 'demo'; + + let lib: LibraryOptions | undefined; + let external: string[]; + let globals: Record; + + if (isVueBundled) { + external = []; + globals = {}; + } else { + external = ['vue']; + globals = { vue: 'Vue' }; + + lib = { + formats: ['es'], + entry: resolve(__dirname, 'src/index.ts'), + name: 'OdkWebForms', + fileName: 'index', + }; + } + + return { base: './', - plugins: [vue(), vueJsx(), cssInjectedByJsPlugin(), bundleFonts()], + plugins: [ + vue(), + vueJsx(), + cssInjectedByJsPlugin(), + unpluginFonts({ + fontsource: { + families: [ + { + /** + * Name of the font family. + * Require the `@fontsource/roboto` package to be installed. + */ + name: 'Roboto', + /** + * Load only a subset of the font family. + */ + weights: [300], + }, + ], + }, + }), + ], resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)), @@ -44,18 +111,11 @@ export default defineConfig((env) => { }, build: { target: 'esnext', - lib: { - formats: ['es'], - entry: resolve(__dirname, 'src/index.ts'), - name: 'OdkWebForms', - fileName: 'index', - }, + lib, rollupOptions: { - external: ['vue'], + external, output: { - globals: { - vue: 'Vue', - }, + globals, }, }, }, @@ -90,12 +150,30 @@ export default defineConfig((env) => { optimizeDeps: { force: true, }, - }; + test: { + browser: { + enabled: BROWSER_ENABLED, + name: BROWSER_NAME!, + provider: 'playwright', + fileParallelism: false, + headless: true, + screenshotFailures: false, + }, + environment: TEST_ENVIRONMENT, + exclude: ['e2e/**'], + root: fileURLToPath(new URL('./', import.meta.url)), - if (env.mode === 'demo') { - const { lib, rollupOptions, ...build } = config.build!; - config.build = build; - } + /** @see {@link webkitFlakinessMitigations} */ + globalSetup, - return config; + // Suppress the console error log about parsing CSS stylesheet + // This is an open issue of jsdom + // see primefaces/primevue#4512 and jsdom/jsdom#2177 + onConsoleLog(log: string, type: 'stderr' | 'stdout'): false | void { + if (log.includes('Error: Could not parse CSS stylesheet') && type === 'stderr') { + return false; + } + }, + }, + }; }); diff --git a/packages/web-forms/vitest.config.ts b/packages/web-forms/vitest.config.ts deleted file mode 100644 index 45e44332e..000000000 --- a/packages/web-forms/vitest.config.ts +++ /dev/null @@ -1,80 +0,0 @@ -import type { CollectionValues } from '@getodk/common/types/collections/CollectionValues.ts'; -import type { VitestTestConfig } from '@getodk/common/types/vitest-config.ts'; -import { existsSync } from 'node:fs'; -import { fileURLToPath } from 'node:url'; -import { configDefaults, defineConfig, mergeConfig } from 'vitest/config'; -import viteConfig from './vite.config'; - -const supportedBrowsers = new Set(['chromium', 'firefox', 'webkit'] as const); - -type SupportedBrowser = CollectionValues; - -const isSupportedBrowser = (browserName: string): browserName is SupportedBrowser => - supportedBrowsers.has(browserName as SupportedBrowser); - -const BROWSER_NAME = (() => { - const envBrowserName = process.env.BROWSER_NAME; - - if (envBrowserName == null) { - return null; - } - - if (isSupportedBrowser(envBrowserName)) { - return envBrowserName; - } - - throw new Error(`Unsupported browser: ${envBrowserName}`); -})(); - -const BROWSER_ENABLED = BROWSER_NAME != null; - -const TEST_ENVIRONMENT = BROWSER_ENABLED ? 'node' : 'jsdom'; - -const globalSetup: string[] = []; - -/** - * @todo this is (hopefully!) temporary. Adds a delay when testing in - * `webkit`, to help mitigate flakiness that seems to be rooted in - * first-run timing issues (where "first" = "no Vite cache"; the issue was - * much more consistently reproducible in a state where - * `node_modules/.vite` is not present). - */ -const webkitFlakinessMitigations = - BROWSER_NAME === 'webkit' && !existsSync('./node_modules/.vite/deps'); - -if (webkitFlakinessMitigations) { - globalSetup.push('./tests/globalSetup/mitigate-webkit-flakiness.ts'); -} - -export default defineConfig((env) => - mergeConfig( - viteConfig(env), - defineConfig({ - test: { - browser: { - enabled: BROWSER_ENABLED, - name: BROWSER_NAME!, - provider: 'playwright', - fileParallelism: false, - headless: true, - screenshotFailures: false, - }, - environment: TEST_ENVIRONMENT, - exclude: [...configDefaults.exclude, 'e2e/**'], - root: fileURLToPath(new URL('./', import.meta.url)), - - /** @see {@link webkitFlakinessMitigations} */ - globalSetup, - - // Suppress the console error log about parsing CSS stylesheet - // This is an open issue of jsdom - // see primefaces/primevue#4512 and jsdom/jsdom#2177 - onConsoleLog(log: string, type: 'stderr' | 'stdout'): false | void { - if (log.includes('Error: Could not parse CSS stylesheet') && type === 'stderr') { - return false; - } - }, - } satisfies VitestTestConfig, - }) - ) -);