@evertondgn/solid-tooling 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +121 -19
- package/dist/playwright-teardown.d.mts +1 -0
- package/dist/playwright-teardown.mjs +23 -0
- package/dist/playwright.d.mts +18 -0
- package/dist/playwright.mjs +158 -0
- package/dist/vitest-setup/browser.d.mts +1 -0
- package/dist/vitest-setup/browser.mjs +5 -0
- package/dist/vitest.d.mts +7 -0
- package/dist/vitest.mjs +129 -0
- package/package.json +19 -6
- package/tsconfig.app.json +21 -0
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# @evertondgn/solid-tooling
|
|
2
2
|
|
|
3
|
-
Lint preset, formatter config and
|
|
4
|
-
built with [Vite+](https://viteplus.dev/guide/).
|
|
3
|
+
Lint preset, formatter config, TypeScript configs and test configs for SolidJS 2
|
|
4
|
+
applications built with [Vite+](https://viteplus.dev/guide/).
|
|
5
5
|
|
|
6
|
-
The package contains the lint, format and
|
|
6
|
+
The package contains the lint, format, TypeScript and test setup of
|
|
7
7
|
[boilerplate_solidjs](https://github.com/everton-dgn/boilerplate_solidjs), a
|
|
8
8
|
SolidJS application template. Applications created from it install the package
|
|
9
9
|
instead of copying the files, so a rule change reaches them through a version
|
|
@@ -27,6 +27,13 @@ with the version in its `devDependencies`.
|
|
|
27
27
|
`eslint-plugin-solid` comes with the package, so the application does not
|
|
28
28
|
declare it.
|
|
29
29
|
|
|
30
|
+
The test entries need the test tools the application already runs:
|
|
31
|
+
|
|
32
|
+
| Entry | The application installs |
|
|
33
|
+
| -------------- | ------------------------------------------------------------------------------ |
|
|
34
|
+
| `./vitest` | `@vitest/browser-playwright`, `@vitest/coverage-v8`, `happy-dom`, `playwright` |
|
|
35
|
+
| `./playwright` | `@playwright/test`, an optional peer dependency pinned like the others |
|
|
36
|
+
|
|
30
37
|
## Install
|
|
31
38
|
|
|
32
39
|
`vp` is the Vite+ CLI. An application built with Vite+ already has `vite-plus`
|
|
@@ -68,6 +75,63 @@ export default defineConfig({ fmt, lint })
|
|
|
68
75
|
|
|
69
76
|
`vp check`, `vp lint` and `vp fmt` read both configs from `vite.config.ts`.
|
|
70
77
|
|
|
78
|
+
## Tests
|
|
79
|
+
|
|
80
|
+
`solidTest` returns the `test` block of `vite.config.ts`, with three Vitest
|
|
81
|
+
projects:
|
|
82
|
+
|
|
83
|
+
| Project | Files | Environment |
|
|
84
|
+
| --------- | -------------------------------- | ------------------------------------------------ |
|
|
85
|
+
| `node` | `src/**/*.node.test.{ts,tsx}` | Node, with stand-ins for the build-only modules |
|
|
86
|
+
| `dom` | `src/**/*.dom.test.{ts,tsx}` | happy-dom at `http://localhost/en` |
|
|
87
|
+
| `browser` | `src/**/*.browser.test.{ts,tsx}` | Chromium through Playwright, with the CSS loaded |
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
// vite.config.ts
|
|
91
|
+
import { solidTest } from '@evertondgn/solid-tooling/vitest'
|
|
92
|
+
|
|
93
|
+
export default defineConfig({
|
|
94
|
+
test: solidTest({ root: import.meta.dirname, plugins: componentPlugins })
|
|
95
|
+
})
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
`plugins` is a function that returns the Vite plugins the `dom` and `browser`
|
|
99
|
+
projects need to compile components: Solid, routes, icons and i18n. The preset
|
|
100
|
+
calls it once per project, because each project starts its own Vite server and a
|
|
101
|
+
plugin instance keeps the state of one server. The preset also sets the coverage
|
|
102
|
+
thresholds, the reporters and the workers on CI, passes `BASE_URL_TEST`, `HOST`
|
|
103
|
+
and `PORT` to the tests when they are set, and resets the Paraglide locale
|
|
104
|
+
before each browser test.
|
|
105
|
+
|
|
106
|
+
The `node` project does not load the Solid and routing plugins, so a plugin of
|
|
107
|
+
the preset serves `server-only`, `virtual:file-routes` and
|
|
108
|
+
`virtual:solid-server-function-handler`. Knip does not know `server-only`, a
|
|
109
|
+
virtual module of `@solidjs/vite-plugin`: list it in `ignoreDependencies`.
|
|
110
|
+
|
|
111
|
+
`definePlaywrightConfig` builds the Playwright config from the application root:
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
// playwright.config.ts
|
|
115
|
+
import { definePlaywrightConfig } from '@evertondgn/solid-tooling/playwright'
|
|
116
|
+
|
|
117
|
+
export default definePlaywrightConfig({ root: import.meta.dirname })
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
It reads `BASE_URL_TEST` from `.env.test`, builds the application (`e2e` mode
|
|
121
|
+
for the fixture routes, `production` with `TEST_PRODUCTION_ROUTES=true`), starts
|
|
122
|
+
the preview, and checks the server log for private markers when the suite ends.
|
|
123
|
+
`TEST_PREBUILT=true` reuses an existing production build.
|
|
124
|
+
|
|
125
|
+
| Option | Default | Use |
|
|
126
|
+
| ---------------- | ----------------- | ---------------------------------------------------------------------- |
|
|
127
|
+
| `testDir` | `src/tests/pages` | Folder of the `*.e2e.test.ts` files |
|
|
128
|
+
| `fixtureServers` | none | Extra servers for the fixture routes, as `{ command, url }` |
|
|
129
|
+
| `suites` | none | Globs of serial suites: `serverLogs`, `markdown` and `publicationLoad` |
|
|
130
|
+
|
|
131
|
+
Each serial suite gets its own project: `markdown` runs with one worker,
|
|
132
|
+
`serverLogs` runs last as the teardown of the others, and `publicationLoad` runs
|
|
133
|
+
alone, against two servers, with `TEST_PUBLICATION_LOAD=true`.
|
|
134
|
+
|
|
71
135
|
## Project layout the preset expects
|
|
72
136
|
|
|
73
137
|
The rules match file paths relative to the folder where lint runs, so run it
|
|
@@ -205,20 +269,26 @@ overrides: [
|
|
|
205
269
|
|
|
206
270
|
## Entry points
|
|
207
271
|
|
|
208
|
-
| Entry
|
|
209
|
-
|
|
|
210
|
-
| `./lint`
|
|
211
|
-
| `./fmt`
|
|
212
|
-
| `./tsconfig.base.json`
|
|
213
|
-
| `./
|
|
214
|
-
| `./
|
|
215
|
-
| `./
|
|
216
|
-
| `./
|
|
217
|
-
| `./
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
plugin
|
|
221
|
-
|
|
272
|
+
| Entry | Content |
|
|
273
|
+
| ------------------------ | ------------------------------------------------------------------------- |
|
|
274
|
+
| `./lint` | `lint`: the lint preset, with the plugins below registered |
|
|
275
|
+
| `./fmt` | `fmt`: the formatter config |
|
|
276
|
+
| `./tsconfig.base.json` | Compiler options, without application paths |
|
|
277
|
+
| `./tsconfig.app.json` | The base plus the `types` and `include` of the boilerplate layout |
|
|
278
|
+
| `./vitest` | `solidTest(options)`, the `test` block of `vite.config.ts` |
|
|
279
|
+
| `./playwright` | `definePlaywrightConfig(options)`, the Playwright config |
|
|
280
|
+
| `./vitest-setup/browser` | Setup file of the browser project, loaded by `./vitest` |
|
|
281
|
+
| `./playwright-teardown` | Server log check, loaded by `./playwright` |
|
|
282
|
+
| `./project-plugin` | The `project` rules |
|
|
283
|
+
| `./backend-plugin` | The `backend` rules |
|
|
284
|
+
| `./architecture-plugin` | The `architecture` rule |
|
|
285
|
+
| `./solid-plugin` | Re-export of `eslint-plugin-solid` |
|
|
286
|
+
| `./css-filename` | `cssFilenameError(path)`, the CSS naming check, for a script outside lint |
|
|
287
|
+
|
|
288
|
+
An application imports `./lint`, `./fmt`, `./vitest`, `./playwright` and one of
|
|
289
|
+
the TypeScript configs. The plugin entries exist because Oxlint loads plugins by
|
|
290
|
+
specifier, from the application; the setup and teardown entries are loaded by
|
|
291
|
+
the test presets.
|
|
222
292
|
|
|
223
293
|
## Formatter
|
|
224
294
|
|
|
@@ -230,8 +300,36 @@ generated route types, SVG and lock files.
|
|
|
230
300
|
|
|
231
301
|
`tsconfig.base.json` targets ES2024 with bundler resolution, keeps JSX for the
|
|
232
302
|
Solid compiler (`jsxImportSource: @solidjs/web`), emits nothing and turns on the
|
|
233
|
-
unused code and unchecked index checks. It has no `paths`, `include` or `types
|
|
234
|
-
|
|
303
|
+
unused code and unchecked index checks. It has no `paths`, `include` or `types`.
|
|
304
|
+
|
|
305
|
+
`tsconfig.app.json` extends the base with the `types` of a boilerplate
|
|
306
|
+
application and an `include` resolved from the application folder with
|
|
307
|
+
`${configDir}`, which needs TypeScript 5.5 or later. Each entry of `types` comes
|
|
308
|
+
from a package the application installs:
|
|
309
|
+
|
|
310
|
+
| Entry of `types` | Package |
|
|
311
|
+
| --------------------------------------- | --------------------------- |
|
|
312
|
+
| `node` | `@types/node` |
|
|
313
|
+
| `vite/client` | `vite` |
|
|
314
|
+
| `vite-plus/test/globals` | `vite-plus` |
|
|
315
|
+
| `@testing-library/jest-dom/vitest` | `@testing-library/jest-dom` |
|
|
316
|
+
| `@solidjs/vite-plugin/boundary-modules` | `@solidjs/vite-plugin` |
|
|
317
|
+
| `@solidjs/vite-plugin/virtual-modules` | `@solidjs/vite-plugin` |
|
|
318
|
+
|
|
319
|
+
The application still declares its `paths`:
|
|
320
|
+
|
|
321
|
+
```json
|
|
322
|
+
{
|
|
323
|
+
"extends": "@evertondgn/solid-tooling/tsconfig.app.json",
|
|
324
|
+
"compilerOptions": {
|
|
325
|
+
"paths": { "@/*": ["./src/*"], "@paraglide/*": ["./paraglide/*"] }
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
Playwright reads the `tsconfig.json` of the test files with its own loader,
|
|
331
|
+
which does not expand `${configDir}`, so paths declared in the package would
|
|
332
|
+
break the `@/` imports of the end-to-end tests.
|
|
235
333
|
|
|
236
334
|
## Known limits
|
|
237
335
|
|
|
@@ -246,6 +344,10 @@ those depend on the application and stay in its `tsconfig.json`.
|
|
|
246
344
|
installed even in an application without translations.
|
|
247
345
|
- Some rule messages point to `docs/architecture.md` and `AGENTS.md`. Those
|
|
248
346
|
files belong to the application created from boilerplate_solidjs.
|
|
347
|
+
- The test presets expect the boilerplate layout: tests named by suffix
|
|
348
|
+
(`.node.test`, `.dom.test`, `.browser.test`, `.e2e.test`), page tests in
|
|
349
|
+
`src/tests/pages/`, Paraglide output in `paraglide/` and `.env.test` at the
|
|
350
|
+
root.
|
|
249
351
|
|
|
250
352
|
## Versions
|
|
251
353
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function checkServerLog(): Promise<void>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { env } from "node:process";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { stripVTControlCharacters } from "node:util";
|
|
4
|
+
// src/playwright/teardown.ts
|
|
5
|
+
const PRIVATE_MARKER = /PRIVATE_[A-Z0-9_]+/u;
|
|
6
|
+
async function checkLog({ file, baseUrl }) {
|
|
7
|
+
if (!file || !baseUrl) throw new Error("Server log file is not configured");
|
|
8
|
+
const log = stripVTControlCharacters(await readFile(file, "utf8"));
|
|
9
|
+
const { host } = new URL(baseUrl);
|
|
10
|
+
if (!log.includes(host)) throw new Error(`Server log does not show the preview startup: ${file}`);
|
|
11
|
+
if (PRIVATE_MARKER.test(log)) throw new Error(`Server log contains a private marker: ${file}`);
|
|
12
|
+
}
|
|
13
|
+
async function checkServerLog() {
|
|
14
|
+
await checkLog({
|
|
15
|
+
file: env.SERVER_LOG_FILE,
|
|
16
|
+
baseUrl: env.BASE_URL_TEST
|
|
17
|
+
});
|
|
18
|
+
if (env.TEST_PUBLICATION_LOAD === "true") await checkLog({
|
|
19
|
+
file: env.SERVER_LOG_SECONDARY,
|
|
20
|
+
baseUrl: env.PUBLICATION_SECONDARY_URL
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
export { checkServerLog as default };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { PlaywrightTestConfig } from "@playwright/test";
|
|
2
|
+
type FixtureServer = {
|
|
3
|
+
command: string;
|
|
4
|
+
url: string;
|
|
5
|
+
};
|
|
6
|
+
type SerialSuites = {
|
|
7
|
+
serverLogs?: string;
|
|
8
|
+
markdown?: string;
|
|
9
|
+
publicationLoad?: string;
|
|
10
|
+
};
|
|
11
|
+
type PlaywrightOptions = {
|
|
12
|
+
root: string;
|
|
13
|
+
testDir?: string;
|
|
14
|
+
fixtureServers?: FixtureServer[];
|
|
15
|
+
suites?: SerialSuites;
|
|
16
|
+
};
|
|
17
|
+
export declare function definePlaywrightConfig({ root, testDir, fixtureServers, suites }: PlaywrightOptions): PlaywrightTestConfig;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { env, loadEnvFile } from "node:process";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { defineConfig, devices } from "@playwright/test";
|
|
5
|
+
import { loadEnv } from "vite-plus";
|
|
6
|
+
// src/playwright/index.ts
|
|
7
|
+
const STARTUP_TIMEOUT = 12e4;
|
|
8
|
+
const SECONDARY_PORT_OFFSET = 2;
|
|
9
|
+
const MAX_PORT = 65535;
|
|
10
|
+
const CI_WORKERS = 2;
|
|
11
|
+
const SECONDARY_LOG = "test-results/server-publication-secondary.log";
|
|
12
|
+
const PREBUILT_GUARD = "if [ -e .vercel/output/static/.vite ]; then echo 'TEST_PREBUILT found an e2e build; run vp run build first' >&2; exit 1; fi && ";
|
|
13
|
+
function readRunMode(suites) {
|
|
14
|
+
const mode = {
|
|
15
|
+
isProduction: env.TEST_PRODUCTION_ROUTES === "true",
|
|
16
|
+
isPublicationLoad: env.TEST_PUBLICATION_LOAD === "true",
|
|
17
|
+
shouldBuild: env.TEST_PREBUILT !== "true"
|
|
18
|
+
};
|
|
19
|
+
if (mode.isPublicationLoad && mode.isProduction) throw new Error("TEST_PUBLICATION_LOAD requires fixture routes");
|
|
20
|
+
if (mode.isPublicationLoad && !suites.publicationLoad) throw new Error("TEST_PUBLICATION_LOAD requires a publicationLoad suite");
|
|
21
|
+
if (!mode.shouldBuild && !mode.isProduction) throw new Error("TEST_PREBUILT requires production routes");
|
|
22
|
+
return mode;
|
|
23
|
+
}
|
|
24
|
+
function readBaseUrl(mode) {
|
|
25
|
+
if (!env.BASE_URL_TEST) throw new Error(".env.test must define BASE_URL_TEST");
|
|
26
|
+
const baseUrl = new URL(env.BASE_URL_TEST);
|
|
27
|
+
if (!baseUrl.port) throw new Error("BASE_URL_TEST must include an explicit port");
|
|
28
|
+
if (mode.isPublicationLoad && Number(baseUrl.port) + SECONDARY_PORT_OFFSET > MAX_PORT) throw new Error("BASE_URL_TEST leaves no port for the secondary server");
|
|
29
|
+
return env.BASE_URL_TEST;
|
|
30
|
+
}
|
|
31
|
+
function readWorkers(mode) {
|
|
32
|
+
if (mode.isPublicationLoad) return 1;
|
|
33
|
+
return env.CI ? CI_WORKERS : void 0;
|
|
34
|
+
}
|
|
35
|
+
function secondaryUrl(baseUrl) {
|
|
36
|
+
const url = new URL(baseUrl);
|
|
37
|
+
url.port = String(Number(url.port) + SECONDARY_PORT_OFFSET);
|
|
38
|
+
return url;
|
|
39
|
+
}
|
|
40
|
+
function buildProjects({ mode, suites }) {
|
|
41
|
+
if (mode.isPublicationLoad) return [{
|
|
42
|
+
name: "publication-load",
|
|
43
|
+
testMatch: suites.publicationLoad
|
|
44
|
+
}];
|
|
45
|
+
if (mode.isProduction) return [{ name: "chromium" }];
|
|
46
|
+
const teardown = suites.serverLogs ? { teardown: "server-logs" } : {};
|
|
47
|
+
const projects = [{
|
|
48
|
+
name: "chromium",
|
|
49
|
+
testIgnore: ["**/*.production.e2e.test.ts", ...[
|
|
50
|
+
suites.serverLogs,
|
|
51
|
+
suites.publicationLoad,
|
|
52
|
+
suites.markdown
|
|
53
|
+
].filter((suite) => suite !== void 0)],
|
|
54
|
+
...teardown
|
|
55
|
+
}];
|
|
56
|
+
if (suites.markdown) projects.push({
|
|
57
|
+
name: "markdown",
|
|
58
|
+
testMatch: suites.markdown,
|
|
59
|
+
fullyParallel: false,
|
|
60
|
+
workers: 1,
|
|
61
|
+
...teardown
|
|
62
|
+
});
|
|
63
|
+
if (suites.serverLogs) projects.push({
|
|
64
|
+
name: "server-logs",
|
|
65
|
+
testMatch: suites.serverLogs,
|
|
66
|
+
fullyParallel: false
|
|
67
|
+
});
|
|
68
|
+
return projects;
|
|
69
|
+
}
|
|
70
|
+
function buildServers({ root, mode, fixtureServers, baseUrl, serverLog }) {
|
|
71
|
+
const buildMode = mode.isProduction ? "production" : "e2e";
|
|
72
|
+
const build = mode.shouldBuild ? `vp run build --mode ${buildMode} && ` : PREBUILT_GUARD;
|
|
73
|
+
const shared = {
|
|
74
|
+
cwd: root,
|
|
75
|
+
reuseExistingServer: false
|
|
76
|
+
};
|
|
77
|
+
const server = {
|
|
78
|
+
...shared,
|
|
79
|
+
timeout: STARTUP_TIMEOUT
|
|
80
|
+
};
|
|
81
|
+
const fixtures = mode.isProduction ? [] : fixtureServers.map((fixture) => ({
|
|
82
|
+
...fixture,
|
|
83
|
+
...shared
|
|
84
|
+
}));
|
|
85
|
+
const { hostname, port } = new URL(baseUrl);
|
|
86
|
+
const secondary = secondaryUrl(baseUrl);
|
|
87
|
+
return [
|
|
88
|
+
...fixtures,
|
|
89
|
+
{
|
|
90
|
+
...server,
|
|
91
|
+
command: `${build}mkdir -p test-results && vp run start --strictPort > ${serverLog} 2>&1`,
|
|
92
|
+
env: {
|
|
93
|
+
HOST: hostname,
|
|
94
|
+
PORT: port,
|
|
95
|
+
NODE_ENV: "production"
|
|
96
|
+
},
|
|
97
|
+
url: baseUrl
|
|
98
|
+
},
|
|
99
|
+
...mode.isPublicationLoad ? [{
|
|
100
|
+
...server,
|
|
101
|
+
command: `vp run start --strictPort > ${SECONDARY_LOG} 2>&1`,
|
|
102
|
+
env: {
|
|
103
|
+
HOST: hostname,
|
|
104
|
+
PORT: secondary.port,
|
|
105
|
+
NODE_ENV: "production"
|
|
106
|
+
},
|
|
107
|
+
url: secondary.href
|
|
108
|
+
}] : []
|
|
109
|
+
];
|
|
110
|
+
}
|
|
111
|
+
function definePlaywrightConfig({ root, testDir = "src/tests/pages", fixtureServers = [], suites = {} }) {
|
|
112
|
+
loadEnvFile(path.join(root, ".env.test"));
|
|
113
|
+
const mode = readRunMode(suites);
|
|
114
|
+
const buildMode = mode.isProduction ? "production" : "e2e";
|
|
115
|
+
Object.assign(env, loadEnv(buildMode, root, "VITE_"));
|
|
116
|
+
const baseUrl = readBaseUrl(mode);
|
|
117
|
+
const serverLog = `test-results/server-${buildMode}.log`;
|
|
118
|
+
env.SERVER_LOG_FILE = path.join(root, serverLog);
|
|
119
|
+
if (mode.isPublicationLoad) {
|
|
120
|
+
env.PUBLICATION_SECONDARY_URL = secondaryUrl(baseUrl).href;
|
|
121
|
+
env.SERVER_LOG_SECONDARY = path.join(root, SECONDARY_LOG);
|
|
122
|
+
}
|
|
123
|
+
const reportFolder = mode.isProduction ? "production" : "e2e";
|
|
124
|
+
return defineConfig({
|
|
125
|
+
testDir: path.join(root, testDir),
|
|
126
|
+
testMatch: mode.isProduction ? "**/*.production.e2e.test.ts" : "**/*.e2e.test.ts",
|
|
127
|
+
outputDir: path.join(root, mode.isProduction ? "test-results/e2e-production" : "test-results/e2e"),
|
|
128
|
+
globalTeardown: fileURLToPath(new URL("playwright-teardown.mjs", import.meta.url)),
|
|
129
|
+
fullyParallel: !mode.isPublicationLoad,
|
|
130
|
+
forbidOnly: true,
|
|
131
|
+
workers: readWorkers(mode),
|
|
132
|
+
reporter: [["list"], ["html", {
|
|
133
|
+
outputFolder: path.join(root, "playwright-report", reportFolder),
|
|
134
|
+
open: "never",
|
|
135
|
+
onlyFailures: Boolean(env.CI)
|
|
136
|
+
}]],
|
|
137
|
+
use: {
|
|
138
|
+
...devices["Desktop Chrome"],
|
|
139
|
+
channel: env.CI ? "chrome" : void 0,
|
|
140
|
+
baseURL: baseUrl,
|
|
141
|
+
locale: "en-US",
|
|
142
|
+
screenshot: "only-on-failure",
|
|
143
|
+
trace: "retain-on-failure"
|
|
144
|
+
},
|
|
145
|
+
projects: buildProjects({
|
|
146
|
+
mode,
|
|
147
|
+
suites
|
|
148
|
+
}),
|
|
149
|
+
webServer: buildServers({
|
|
150
|
+
root,
|
|
151
|
+
mode,
|
|
152
|
+
fixtureServers,
|
|
153
|
+
baseUrl,
|
|
154
|
+
serverLog
|
|
155
|
+
})
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
export { definePlaywrightConfig };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
package/dist/vitest.mjs
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { env } from "node:process";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { playwright } from "vite-plus/test/browser-playwright";
|
|
5
|
+
// src/vitest/index.ts
|
|
6
|
+
const CI_WORKERS = 2;
|
|
7
|
+
const STUB_PREFIX = "\0solid-tooling-stub:";
|
|
8
|
+
const NODE_STUBS = /* @__PURE__ */ new Map([
|
|
9
|
+
["server-only", "export default undefined"],
|
|
10
|
+
["virtual:file-routes", "export const pageRoutes = []\nexport default []"],
|
|
11
|
+
["virtual:solid-server-function-handler", "export const endpoint = '/_server'"]
|
|
12
|
+
]);
|
|
13
|
+
const TEST_ENV_KEYS = [
|
|
14
|
+
"BASE_URL_TEST",
|
|
15
|
+
"HOST",
|
|
16
|
+
"PORT"
|
|
17
|
+
];
|
|
18
|
+
function packageFile(name) {
|
|
19
|
+
return fileURLToPath(new URL(name, import.meta.url));
|
|
20
|
+
}
|
|
21
|
+
function nodeStubs() {
|
|
22
|
+
return {
|
|
23
|
+
name: "solid-tooling:node-stubs",
|
|
24
|
+
enforce: "pre",
|
|
25
|
+
resolveId: (id) => NODE_STUBS.has(id) ? `${STUB_PREFIX}${id}` : void 0,
|
|
26
|
+
load: (id) => id.startsWith(STUB_PREFIX) ? NODE_STUBS.get(id.slice(20)) : void 0
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function readTestEnv() {
|
|
30
|
+
return Object.fromEntries(TEST_ENV_KEYS.flatMap((key) => {
|
|
31
|
+
const value = env[key];
|
|
32
|
+
return value === void 0 ? [] : [[key, value]];
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
function solidTest({ root, plugins }) {
|
|
36
|
+
return {
|
|
37
|
+
pool: "threads",
|
|
38
|
+
maxWorkers: env.CI ? CI_WORKERS : void 0,
|
|
39
|
+
css: false,
|
|
40
|
+
globals: true,
|
|
41
|
+
restoreMocks: true,
|
|
42
|
+
unstubGlobals: true,
|
|
43
|
+
unstubEnvs: true,
|
|
44
|
+
expect: {
|
|
45
|
+
requireAssertions: true,
|
|
46
|
+
poll: { interval: 10 }
|
|
47
|
+
},
|
|
48
|
+
env: readTestEnv(),
|
|
49
|
+
coverage: {
|
|
50
|
+
provider: "v8",
|
|
51
|
+
reporter: ["text", "html"],
|
|
52
|
+
thresholds: {
|
|
53
|
+
lines: 80,
|
|
54
|
+
functions: 80,
|
|
55
|
+
branches: 75,
|
|
56
|
+
statements: 80
|
|
57
|
+
},
|
|
58
|
+
include: ["src/**/*.{ts,tsx}"],
|
|
59
|
+
exclude: [
|
|
60
|
+
"src/**/*.d.ts",
|
|
61
|
+
"src/**/{constants,types,@types}/**",
|
|
62
|
+
"src/**/{constants,types}.{ts,tsx}",
|
|
63
|
+
"src/**/__tests__/**",
|
|
64
|
+
"src/tests/**",
|
|
65
|
+
"src/App.tsx",
|
|
66
|
+
"src/Document.tsx",
|
|
67
|
+
"src/entry-server.tsx",
|
|
68
|
+
"src/entry-client.tsx",
|
|
69
|
+
"src/router.ts"
|
|
70
|
+
]
|
|
71
|
+
},
|
|
72
|
+
reporters: env.GITHUB_ACTIONS ? ["default", "github-actions"] : ["verbose"],
|
|
73
|
+
projects: [
|
|
74
|
+
{
|
|
75
|
+
plugins: [nodeStubs()],
|
|
76
|
+
test: {
|
|
77
|
+
name: {
|
|
78
|
+
label: "node",
|
|
79
|
+
color: "cyan"
|
|
80
|
+
},
|
|
81
|
+
environment: "node",
|
|
82
|
+
include: ["src/**/*.node.test.{ts,tsx}"]
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
plugins: plugins(),
|
|
87
|
+
test: {
|
|
88
|
+
name: {
|
|
89
|
+
label: "dom",
|
|
90
|
+
color: "magenta"
|
|
91
|
+
},
|
|
92
|
+
environment: "happy-dom",
|
|
93
|
+
environmentOptions: { happyDOM: { url: "http://localhost/en" } },
|
|
94
|
+
include: ["src/**/*.dom.test.{ts,tsx}"]
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
plugins: plugins(),
|
|
99
|
+
resolve: { alias: [{
|
|
100
|
+
find: /^@paraglide\//u,
|
|
101
|
+
replacement: `${path.join(root, "paraglide")}/`
|
|
102
|
+
}] },
|
|
103
|
+
test: {
|
|
104
|
+
css: true,
|
|
105
|
+
name: {
|
|
106
|
+
label: "browser",
|
|
107
|
+
color: "yellow"
|
|
108
|
+
},
|
|
109
|
+
setupFiles: [packageFile("vitest-setup/browser.mjs")],
|
|
110
|
+
include: ["src/**/*.browser.test.{ts,tsx}"],
|
|
111
|
+
browser: {
|
|
112
|
+
enabled: true,
|
|
113
|
+
headless: true,
|
|
114
|
+
trace: {
|
|
115
|
+
mode: "retain-on-failure",
|
|
116
|
+
tracesDir: path.join(root, "test-results/browser-traces")
|
|
117
|
+
},
|
|
118
|
+
provider: playwright({
|
|
119
|
+
contextOptions: { locale: "en-US" },
|
|
120
|
+
launchOptions: env.CI ? { channel: "chrome" } : {}
|
|
121
|
+
}),
|
|
122
|
+
instances: [{ browser: "chromium" }]
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
]
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
export { solidTest };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evertondgn/solid-tooling",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Lint, formatter and
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Lint, formatter, TypeScript and test presets for SolidJS applications built with Vite+.",
|
|
5
5
|
"author": "Éverton Toffanetto",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
"type": "module",
|
|
20
20
|
"files": [
|
|
21
21
|
"dist",
|
|
22
|
-
"tsconfig.base.json"
|
|
22
|
+
"tsconfig.base.json",
|
|
23
|
+
"tsconfig.app.json"
|
|
23
24
|
],
|
|
24
25
|
"exports": {
|
|
25
26
|
"./architecture-plugin": "./dist/architecture-plugin.mjs",
|
|
@@ -27,10 +28,15 @@
|
|
|
27
28
|
"./css-filename": "./dist/css-filename.mjs",
|
|
28
29
|
"./fmt": "./dist/fmt.mjs",
|
|
29
30
|
"./lint": "./dist/lint.mjs",
|
|
31
|
+
"./playwright": "./dist/playwright.mjs",
|
|
32
|
+
"./playwright-teardown": "./dist/playwright-teardown.mjs",
|
|
30
33
|
"./project-plugin": "./dist/project-plugin.mjs",
|
|
31
34
|
"./solid-plugin": "./dist/solid-plugin.mjs",
|
|
35
|
+
"./vitest": "./dist/vitest.mjs",
|
|
36
|
+
"./vitest-setup/browser": "./dist/vitest-setup/browser.mjs",
|
|
32
37
|
"./package.json": "./package.json",
|
|
33
|
-
"./tsconfig.base.json": "./tsconfig.base.json"
|
|
38
|
+
"./tsconfig.base.json": "./tsconfig.base.json",
|
|
39
|
+
"./tsconfig.app.json": "./tsconfig.app.json"
|
|
34
40
|
},
|
|
35
41
|
"publishConfig": {
|
|
36
42
|
"access": "public"
|
|
@@ -46,13 +52,20 @@
|
|
|
46
52
|
},
|
|
47
53
|
"peerDependencies": {
|
|
48
54
|
"@inlang/paraglide-js": "3.2.2",
|
|
49
|
-
"vite-plus": "1.6.0"
|
|
55
|
+
"vite-plus": "1.6.0",
|
|
56
|
+
"@playwright/test": "1.65.0"
|
|
50
57
|
},
|
|
51
58
|
"devDependencies": {
|
|
52
59
|
"@inlang/paraglide-js": "3.2.2",
|
|
53
60
|
"@types/node": "24.19.2",
|
|
54
61
|
"typescript": "7.0.2",
|
|
55
62
|
"valibot": "1.5.0",
|
|
56
|
-
"vite-plus": "1.6.0"
|
|
63
|
+
"vite-plus": "1.6.0",
|
|
64
|
+
"@playwright/test": "1.65.0"
|
|
65
|
+
},
|
|
66
|
+
"peerDependenciesMeta": {
|
|
67
|
+
"@playwright/test": {
|
|
68
|
+
"optional": true
|
|
69
|
+
}
|
|
57
70
|
}
|
|
58
71
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"types": [
|
|
5
|
+
"node",
|
|
6
|
+
"vite/client",
|
|
7
|
+
"vite-plus/test/globals",
|
|
8
|
+
"@testing-library/jest-dom/vitest",
|
|
9
|
+
"@solidjs/vite-plugin/boundary-modules",
|
|
10
|
+
"@solidjs/vite-plugin/virtual-modules"
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
"include": [
|
|
14
|
+
"${configDir}/src",
|
|
15
|
+
"${configDir}/env.ts",
|
|
16
|
+
"${configDir}/solid-env.d.ts",
|
|
17
|
+
"${configDir}/vite.config.ts",
|
|
18
|
+
"${configDir}/playwright.config.ts",
|
|
19
|
+
"${configDir}/tooling/**/*.ts"
|
|
20
|
+
]
|
|
21
|
+
}
|