ads-fe 0.0.1
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 +99 -0
- package/dist/cli.js +545 -0
- package/dist/meta.js +93 -0
- package/package.json +43 -0
- package/skill.md +66 -0
- package/skills/core/SKILL.md +66 -0
- package/skills/core/references/app-development.md +45 -0
- package/skills/core/references/git.md +66 -0
- package/skills/core/references/monorepo.md +124 -0
- package/skills/element-plus-vue3/LICENSE.md +405 -0
- package/skills/element-plus-vue3/LICENSE.txt +202 -0
- package/skills/element-plus-vue3/SKILL.md +218 -0
- package/skills/element-plus-vue3/SYNC.md +5 -0
- package/skills/element-plus-vue3/api/component-api.md +94 -0
- package/skills/element-plus-vue3/api/global-config.md +89 -0
- package/skills/element-plus-vue3/api/props-and-events.md +101 -0
- package/skills/element-plus-vue3/examples/components/button.md +99 -0
- package/skills/element-plus-vue3/examples/components/date-picker.md +115 -0
- package/skills/element-plus-vue3/examples/components/dialog.md +106 -0
- package/skills/element-plus-vue3/examples/components/form.md +127 -0
- package/skills/element-plus-vue3/examples/components/input.md +123 -0
- package/skills/element-plus-vue3/examples/components/message.md +93 -0
- package/skills/element-plus-vue3/examples/components/overview.md +59 -0
- package/skills/element-plus-vue3/examples/components/select.md +133 -0
- package/skills/element-plus-vue3/examples/components/table.md +166 -0
- package/skills/element-plus-vue3/examples/guide/design.md +68 -0
- package/skills/element-plus-vue3/examples/guide/global-config.md +95 -0
- package/skills/element-plus-vue3/examples/guide/i18n.md +95 -0
- package/skills/element-plus-vue3/examples/guide/installation.md +110 -0
- package/skills/element-plus-vue3/examples/guide/quick-start.md +103 -0
- package/skills/element-plus-vue3/examples/guide/theme.md +78 -0
- package/skills/element-plus-vue3/templates/component-usage.md +92 -0
- package/skills/element-plus-vue3/templates/installation.md +82 -0
- package/skills/element-plus-vue3/templates/project-setup.md +83 -0
- package/skills/node/LICENSE.md +21 -0
- package/skills/node/SKILL.md +94 -0
- package/skills/node/SYNC.md +5 -0
- package/skills/node/rules/assets/graceful-server.test.ts +88 -0
- package/skills/node/rules/assets/graceful-server.ts +80 -0
- package/skills/node/rules/async-patterns.md +136 -0
- package/skills/node/rules/caching.md +198 -0
- package/skills/node/rules/environment.md +253 -0
- package/skills/node/rules/error-handling.md +164 -0
- package/skills/node/rules/flaky-tests.md +439 -0
- package/skills/node/rules/graceful-shutdown.md +204 -0
- package/skills/node/rules/logging.md +205 -0
- package/skills/node/rules/modules.md +105 -0
- package/skills/node/rules/node-modules-exploration.md +172 -0
- package/skills/node/rules/performance.md +130 -0
- package/skills/node/rules/profiling.md +183 -0
- package/skills/node/rules/streams.md +213 -0
- package/skills/node/rules/stuck-processes-and-tests.md +124 -0
- package/skills/node/rules/testing.md +218 -0
- package/skills/node/rules/typescript.md +262 -0
- package/skills/node/tile.json +11 -0
- package/skills/nuxt/GENERATION.md +5 -0
- package/skills/nuxt/LICENSE.md +21 -0
- package/skills/nuxt/SKILL.md +55 -0
- package/skills/nuxt/SYNC.md +5 -0
- package/skills/nuxt/references/advanced-hooks.md +289 -0
- package/skills/nuxt/references/advanced-layers.md +299 -0
- package/skills/nuxt/references/advanced-module-authoring.md +554 -0
- package/skills/nuxt/references/best-practices-data-fetching.md +357 -0
- package/skills/nuxt/references/best-practices-ssr.md +355 -0
- package/skills/nuxt/references/core-cli.md +263 -0
- package/skills/nuxt/references/core-config.md +162 -0
- package/skills/nuxt/references/core-data-fetching.md +236 -0
- package/skills/nuxt/references/core-deployment.md +224 -0
- package/skills/nuxt/references/core-directory-structure.md +269 -0
- package/skills/nuxt/references/core-modules.md +292 -0
- package/skills/nuxt/references/core-routing.md +226 -0
- package/skills/nuxt/references/features-components-autoimport.md +328 -0
- package/skills/nuxt/references/features-components.md +264 -0
- package/skills/nuxt/references/features-composables.md +276 -0
- package/skills/nuxt/references/features-server.md +265 -0
- package/skills/nuxt/references/features-state.md +194 -0
- package/skills/nuxt/references/rendering-modes.md +237 -0
- package/skills/pinia/GENERATION.md +5 -0
- package/skills/pinia/LICENSE.md +21 -0
- package/skills/pinia/SKILL.md +59 -0
- package/skills/pinia/SYNC.md +5 -0
- package/skills/pinia/references/advanced-hmr.md +61 -0
- package/skills/pinia/references/advanced-nuxt.md +119 -0
- package/skills/pinia/references/advanced-ssr.md +121 -0
- package/skills/pinia/references/best-practices-outside-component.md +115 -0
- package/skills/pinia/references/best-practices-testing.md +212 -0
- package/skills/pinia/references/core-stores.md +389 -0
- package/skills/pinia/references/features-composables.md +114 -0
- package/skills/pinia/references/features-composing-stores.md +134 -0
- package/skills/pinia/references/features-plugins.md +203 -0
- package/skills/pnpm/GENERATION.md +5 -0
- package/skills/pnpm/LICENSE.md +21 -0
- package/skills/pnpm/SKILL.md +42 -0
- package/skills/pnpm/SYNC.md +5 -0
- package/skills/pnpm/references/best-practices-ci.md +285 -0
- package/skills/pnpm/references/best-practices-migration.md +291 -0
- package/skills/pnpm/references/best-practices-performance.md +284 -0
- package/skills/pnpm/references/core-cli.md +229 -0
- package/skills/pnpm/references/core-config.md +188 -0
- package/skills/pnpm/references/core-store.md +179 -0
- package/skills/pnpm/references/core-workspaces.md +205 -0
- package/skills/pnpm/references/features-aliases.md +168 -0
- package/skills/pnpm/references/features-catalogs.md +159 -0
- package/skills/pnpm/references/features-hooks.md +233 -0
- package/skills/pnpm/references/features-overrides.md +184 -0
- package/skills/pnpm/references/features-patches.md +201 -0
- package/skills/pnpm/references/features-peer-deps.md +250 -0
- package/skills/slidev/LICENSE.md +21 -0
- package/skills/slidev/README.md +61 -0
- package/skills/slidev/SKILL.md +189 -0
- package/skills/slidev/SYNC.md +5 -0
- package/skills/slidev/references/animation-click-marker.md +37 -0
- package/skills/slidev/references/animation-drawing.md +68 -0
- package/skills/slidev/references/animation-rough-marker.md +53 -0
- package/skills/slidev/references/api-slide-hooks.md +37 -0
- package/skills/slidev/references/build-og-image.md +36 -0
- package/skills/slidev/references/build-pdf.md +40 -0
- package/skills/slidev/references/build-remote-assets.md +34 -0
- package/skills/slidev/references/build-seo-meta.md +43 -0
- package/skills/slidev/references/code-groups.md +64 -0
- package/skills/slidev/references/code-import-snippet.md +55 -0
- package/skills/slidev/references/code-line-highlighting.md +50 -0
- package/skills/slidev/references/code-line-numbers.md +46 -0
- package/skills/slidev/references/code-magic-move.md +57 -0
- package/skills/slidev/references/code-max-height.md +37 -0
- package/skills/slidev/references/code-twoslash.md +42 -0
- package/skills/slidev/references/core-animations.md +196 -0
- package/skills/slidev/references/core-cli.md +140 -0
- package/skills/slidev/references/core-components.md +197 -0
- package/skills/slidev/references/core-exporting.md +148 -0
- package/skills/slidev/references/core-frontmatter.md +195 -0
- package/skills/slidev/references/core-global-context.md +155 -0
- package/skills/slidev/references/core-headmatter.md +188 -0
- package/skills/slidev/references/core-hosting.md +152 -0
- package/skills/slidev/references/core-layouts.md +286 -0
- package/skills/slidev/references/core-syntax.md +155 -0
- package/skills/slidev/references/diagram-latex.md +55 -0
- package/skills/slidev/references/diagram-mermaid.md +44 -0
- package/skills/slidev/references/diagram-plantuml.md +45 -0
- package/skills/slidev/references/editor-monaco-run.md +44 -0
- package/skills/slidev/references/editor-monaco-write.md +24 -0
- package/skills/slidev/references/editor-monaco.md +50 -0
- package/skills/slidev/references/editor-prettier.md +40 -0
- package/skills/slidev/references/editor-side.md +23 -0
- package/skills/slidev/references/editor-vscode.md +55 -0
- package/skills/slidev/references/layout-canvas-size.md +25 -0
- package/skills/slidev/references/layout-draggable.md +57 -0
- package/skills/slidev/references/layout-global-layers.md +50 -0
- package/skills/slidev/references/layout-slots.md +75 -0
- package/skills/slidev/references/layout-transform.md +33 -0
- package/skills/slidev/references/layout-zoom.md +39 -0
- package/skills/slidev/references/presenter-notes-ruby.md +35 -0
- package/skills/slidev/references/presenter-recording.md +30 -0
- package/skills/slidev/references/presenter-remote.md +40 -0
- package/skills/slidev/references/presenter-timer.md +34 -0
- package/skills/slidev/references/style-direction.md +34 -0
- package/skills/slidev/references/style-icons.md +46 -0
- package/skills/slidev/references/style-scoped.md +50 -0
- package/skills/slidev/references/syntax-block-frontmatter.md +39 -0
- package/skills/slidev/references/syntax-comark.md +51 -0
- package/skills/slidev/references/syntax-frontmatter-merging.md +49 -0
- package/skills/slidev/references/syntax-importing-slides.md +60 -0
- package/skills/slidev/references/tool-eject-theme.md +27 -0
- package/skills/tsdown/LICENSE.md +22 -0
- package/skills/tsdown/README.md +77 -0
- package/skills/tsdown/SKILL.md +416 -0
- package/skills/tsdown/SYNC.md +5 -0
- package/skills/tsdown/references/README.md +139 -0
- package/skills/tsdown/references/advanced-benchmark.md +8 -0
- package/skills/tsdown/references/advanced-ci.md +89 -0
- package/skills/tsdown/references/advanced-hooks.md +363 -0
- package/skills/tsdown/references/advanced-plugins.md +381 -0
- package/skills/tsdown/references/advanced-programmatic.md +378 -0
- package/skills/tsdown/references/advanced-rolldown-options.md +117 -0
- package/skills/tsdown/references/guide-getting-started.md +183 -0
- package/skills/tsdown/references/guide-introduction.md +42 -0
- package/skills/tsdown/references/guide-migrate-from-tsup.md +199 -0
- package/skills/tsdown/references/option-cjs-default.md +98 -0
- package/skills/tsdown/references/option-cleaning.md +275 -0
- package/skills/tsdown/references/option-config-file.md +291 -0
- package/skills/tsdown/references/option-css.md +301 -0
- package/skills/tsdown/references/option-dependencies.md +385 -0
- package/skills/tsdown/references/option-dts.md +251 -0
- package/skills/tsdown/references/option-entry.md +211 -0
- package/skills/tsdown/references/option-exe.md +120 -0
- package/skills/tsdown/references/option-lint.md +127 -0
- package/skills/tsdown/references/option-log-level.md +91 -0
- package/skills/tsdown/references/option-minification.md +177 -0
- package/skills/tsdown/references/option-output-directory.md +272 -0
- package/skills/tsdown/references/option-output-format.md +183 -0
- package/skills/tsdown/references/option-package-exports.md +320 -0
- package/skills/tsdown/references/option-platform.md +256 -0
- package/skills/tsdown/references/option-root.md +88 -0
- package/skills/tsdown/references/option-shims.md +299 -0
- package/skills/tsdown/references/option-sourcemap.md +301 -0
- package/skills/tsdown/references/option-target.md +222 -0
- package/skills/tsdown/references/option-tree-shaking.md +335 -0
- package/skills/tsdown/references/option-unbundle.md +310 -0
- package/skills/tsdown/references/option-watch-mode.md +261 -0
- package/skills/tsdown/references/recipe-react.md +338 -0
- package/skills/tsdown/references/recipe-solid.md +42 -0
- package/skills/tsdown/references/recipe-svelte.md +54 -0
- package/skills/tsdown/references/recipe-vue.md +387 -0
- package/skills/tsdown/references/recipe-wasm.md +125 -0
- package/skills/tsdown/references/reference-cli.md +472 -0
- package/skills/turborepo/LICENSE.md +7 -0
- package/skills/turborepo/SKILL.md +951 -0
- package/skills/turborepo/SYNC.md +5 -0
- package/skills/turborepo/command/turborepo.md +70 -0
- package/skills/turborepo/references/best-practices/RULE.md +241 -0
- package/skills/turborepo/references/best-practices/dependencies.md +246 -0
- package/skills/turborepo/references/best-practices/packages.md +335 -0
- package/skills/turborepo/references/best-practices/structure.md +297 -0
- package/skills/turborepo/references/boundaries/RULE.md +126 -0
- package/skills/turborepo/references/caching/RULE.md +153 -0
- package/skills/turborepo/references/caching/gotchas.md +190 -0
- package/skills/turborepo/references/caching/remote-cache.md +127 -0
- package/skills/turborepo/references/ci/RULE.md +79 -0
- package/skills/turborepo/references/ci/github-actions.md +162 -0
- package/skills/turborepo/references/ci/patterns.md +145 -0
- package/skills/turborepo/references/ci/vercel.md +103 -0
- package/skills/turborepo/references/cli/RULE.md +100 -0
- package/skills/turborepo/references/cli/commands.md +297 -0
- package/skills/turborepo/references/configuration/RULE.md +235 -0
- package/skills/turborepo/references/configuration/global-options.md +239 -0
- package/skills/turborepo/references/configuration/gotchas.md +368 -0
- package/skills/turborepo/references/configuration/tasks.md +325 -0
- package/skills/turborepo/references/environment/RULE.md +123 -0
- package/skills/turborepo/references/environment/gotchas.md +175 -0
- package/skills/turborepo/references/environment/modes.md +101 -0
- package/skills/turborepo/references/filtering/RULE.md +148 -0
- package/skills/turborepo/references/filtering/patterns.md +152 -0
- package/skills/turborepo/references/watch/RULE.md +99 -0
- package/skills/vite/GENERATION.md +5 -0
- package/skills/vite/LICENSE.md +21 -0
- package/skills/vite/SKILL.md +72 -0
- package/skills/vite/SYNC.md +5 -0
- package/skills/vite/references/build-and-ssr.md +164 -0
- package/skills/vite/references/core-config.md +162 -0
- package/skills/vite/references/core-features.md +205 -0
- package/skills/vite/references/core-plugin-api.md +235 -0
- package/skills/vite/references/environment-api.md +108 -0
- package/skills/vite/references/rolldown-migration.md +157 -0
- package/skills/vitepress/GENERATION.md +5 -0
- package/skills/vitepress/LICENSE.md +21 -0
- package/skills/vitepress/SKILL.md +65 -0
- package/skills/vitepress/SYNC.md +5 -0
- package/skills/vitepress/references/advanced-i18n.md +299 -0
- package/skills/vitepress/references/advanced-ssr.md +228 -0
- package/skills/vitepress/references/core-cli.md +119 -0
- package/skills/vitepress/references/core-config.md +189 -0
- package/skills/vitepress/references/core-markdown.md +277 -0
- package/skills/vitepress/references/core-routing.md +169 -0
- package/skills/vitepress/references/features-code-blocks.md +243 -0
- package/skills/vitepress/references/features-data-loading.md +220 -0
- package/skills/vitepress/references/features-dynamic-routes.md +235 -0
- package/skills/vitepress/references/features-vue.md +224 -0
- package/skills/vitepress/references/recipes-deploy.md +240 -0
- package/skills/vitepress/references/theme-config.md +315 -0
- package/skills/vitepress/references/theme-custom.md +269 -0
- package/skills/vitepress/references/theme-customization.md +290 -0
- package/skills/vitest/GENERATION.md +5 -0
- package/skills/vitest/LICENSE.md +21 -0
- package/skills/vitest/SKILL.md +52 -0
- package/skills/vitest/SYNC.md +5 -0
- package/skills/vitest/references/advanced-environments.md +264 -0
- package/skills/vitest/references/advanced-projects.md +300 -0
- package/skills/vitest/references/advanced-type-testing.md +237 -0
- package/skills/vitest/references/advanced-vi.md +249 -0
- package/skills/vitest/references/core-cli.md +166 -0
- package/skills/vitest/references/core-config.md +174 -0
- package/skills/vitest/references/core-describe.md +193 -0
- package/skills/vitest/references/core-expect.md +219 -0
- package/skills/vitest/references/core-hooks.md +244 -0
- package/skills/vitest/references/core-test-api.md +233 -0
- package/skills/vitest/references/features-concurrency.md +250 -0
- package/skills/vitest/references/features-context.md +238 -0
- package/skills/vitest/references/features-coverage.md +207 -0
- package/skills/vitest/references/features-filtering.md +211 -0
- package/skills/vitest/references/features-mocking.md +265 -0
- package/skills/vitest/references/features-snapshots.md +207 -0
- package/skills/vue/GENERATION.md +5 -0
- package/skills/vue/LICENSE.md +21 -0
- package/skills/vue/SKILL.md +84 -0
- package/skills/vue/SYNC.md +5 -0
- package/skills/vue/references/advanced-patterns.md +314 -0
- package/skills/vue/references/core-new-apis.md +264 -0
- package/skills/vue/references/script-setup-macros.md +204 -0
- package/skills/vue-best-practices/LICENSE.md +21 -0
- package/skills/vue-best-practices/SKILL.md +154 -0
- package/skills/vue-best-practices/SYNC.md +5 -0
- package/skills/vue-best-practices/references/animation-class-based-technique.md +254 -0
- package/skills/vue-best-practices/references/animation-state-driven-technique.md +291 -0
- package/skills/vue-best-practices/references/component-async.md +97 -0
- package/skills/vue-best-practices/references/component-data-flow.md +307 -0
- package/skills/vue-best-practices/references/component-fallthrough-attrs.md +174 -0
- package/skills/vue-best-practices/references/component-keep-alive.md +137 -0
- package/skills/vue-best-practices/references/component-slots.md +216 -0
- package/skills/vue-best-practices/references/component-suspense.md +228 -0
- package/skills/vue-best-practices/references/component-teleport.md +108 -0
- package/skills/vue-best-practices/references/component-transition-group.md +128 -0
- package/skills/vue-best-practices/references/component-transition.md +125 -0
- package/skills/vue-best-practices/references/composables.md +290 -0
- package/skills/vue-best-practices/references/directives.md +162 -0
- package/skills/vue-best-practices/references/perf-avoid-component-abstraction-in-lists.md +159 -0
- package/skills/vue-best-practices/references/perf-v-once-v-memo-directives.md +182 -0
- package/skills/vue-best-practices/references/perf-virtualize-large-lists.md +187 -0
- package/skills/vue-best-practices/references/plugins.md +166 -0
- package/skills/vue-best-practices/references/reactivity.md +344 -0
- package/skills/vue-best-practices/references/render-functions.md +201 -0
- package/skills/vue-best-practices/references/sfc.md +310 -0
- package/skills/vue-best-practices/references/state-management.md +135 -0
- package/skills/vue-best-practices/references/updated-hook-performance.md +187 -0
- package/skills/vue-router-best-practices/LICENSE.md +21 -0
- package/skills/vue-router-best-practices/SKILL.md +23 -0
- package/skills/vue-router-best-practices/SYNC.md +5 -0
- package/skills/vue-router-best-practices/reference/router-beforeenter-no-param-trigger.md +167 -0
- package/skills/vue-router-best-practices/reference/router-beforerouteenter-no-this.md +176 -0
- package/skills/vue-router-best-practices/reference/router-guard-async-await-pattern.md +227 -0
- package/skills/vue-router-best-practices/reference/router-navigation-guard-infinite-loop.md +187 -0
- package/skills/vue-router-best-practices/reference/router-navigation-guard-next-deprecated.md +150 -0
- package/skills/vue-router-best-practices/reference/router-param-change-no-lifecycle.md +181 -0
- package/skills/vue-router-best-practices/reference/router-simple-routing-cleanup.md +209 -0
- package/skills/vue-router-best-practices/reference/router-use-vue-router-for-production.md +183 -0
- package/skills/vue-testing-best-practices/LICENSE.md +21 -0
- package/skills/vue-testing-best-practices/SKILL.md +29 -0
- package/skills/vue-testing-best-practices/SYNC.md +5 -0
- package/skills/vue-testing-best-practices/reference/async-component-testing.md +163 -0
- package/skills/vue-testing-best-practices/reference/teleport-testing-complexity.md +158 -0
- package/skills/vue-testing-best-practices/reference/testing-async-await-flushpromises.md +175 -0
- package/skills/vue-testing-best-practices/reference/testing-browser-vs-node-runners.md +208 -0
- package/skills/vue-testing-best-practices/reference/testing-component-blackbox-approach.md +144 -0
- package/skills/vue-testing-best-practices/reference/testing-composables-helper-wrapper.md +238 -0
- package/skills/vue-testing-best-practices/reference/testing-e2e-playwright-recommended.md +242 -0
- package/skills/vue-testing-best-practices/reference/testing-no-snapshot-only.md +197 -0
- package/skills/vue-testing-best-practices/reference/testing-pinia-store-setup.md +228 -0
- package/skills/vue-testing-best-practices/reference/testing-suspense-async-components.md +229 -0
- package/skills/vue-testing-best-practices/reference/testing-vitest-recommended-for-vue.md +204 -0
- package/skills/vueuse-functions/LICENSE.md +21 -0
- package/skills/vueuse-functions/SKILL.md +419 -0
- package/skills/vueuse-functions/SYNC.md +5 -0
- package/skills/vueuse-functions/references/computedAsync.md +195 -0
- package/skills/vueuse-functions/references/computedEager.md +62 -0
- package/skills/vueuse-functions/references/computedInject.md +137 -0
- package/skills/vueuse-functions/references/computedWithControl.md +98 -0
- package/skills/vueuse-functions/references/createEventHook.md +86 -0
- package/skills/vueuse-functions/references/createGenericProjection.md +25 -0
- package/skills/vueuse-functions/references/createGlobalState.md +95 -0
- package/skills/vueuse-functions/references/createInjectionState.md +226 -0
- package/skills/vueuse-functions/references/createProjection.md +31 -0
- package/skills/vueuse-functions/references/createRef.md +54 -0
- package/skills/vueuse-functions/references/createReusableTemplate.md +361 -0
- package/skills/vueuse-functions/references/createSharedComposable.md +42 -0
- package/skills/vueuse-functions/references/createTemplatePromise.md +306 -0
- package/skills/vueuse-functions/references/createUnrefFn.md +51 -0
- package/skills/vueuse-functions/references/extendRef.md +76 -0
- package/skills/vueuse-functions/references/from.md +80 -0
- package/skills/vueuse-functions/references/get.md +30 -0
- package/skills/vueuse-functions/references/injectLocal.md +35 -0
- package/skills/vueuse-functions/references/isDefined.md +31 -0
- package/skills/vueuse-functions/references/logicAnd.md +40 -0
- package/skills/vueuse-functions/references/logicNot.md +36 -0
- package/skills/vueuse-functions/references/logicOr.md +40 -0
- package/skills/vueuse-functions/references/makeDestructurable.md +41 -0
- package/skills/vueuse-functions/references/onClickOutside.md +228 -0
- package/skills/vueuse-functions/references/onElementRemoval.md +88 -0
- package/skills/vueuse-functions/references/onKeyStroke.md +212 -0
- package/skills/vueuse-functions/references/onLongPress.md +235 -0
- package/skills/vueuse-functions/references/onStartTyping.md +53 -0
- package/skills/vueuse-functions/references/provideLocal.md +37 -0
- package/skills/vueuse-functions/references/reactify.md +144 -0
- package/skills/vueuse-functions/references/reactifyObject.md +62 -0
- package/skills/vueuse-functions/references/reactiveComputed.md +34 -0
- package/skills/vueuse-functions/references/reactiveOmit.md +86 -0
- package/skills/vueuse-functions/references/reactivePick.md +106 -0
- package/skills/vueuse-functions/references/refAutoReset.md +46 -0
- package/skills/vueuse-functions/references/refDebounced.md +81 -0
- package/skills/vueuse-functions/references/refDefault.md +36 -0
- package/skills/vueuse-functions/references/refManualReset.md +48 -0
- package/skills/vueuse-functions/references/refThrottled.md +99 -0
- package/skills/vueuse-functions/references/refWithControl.md +146 -0
- package/skills/vueuse-functions/references/set.md +30 -0
- package/skills/vueuse-functions/references/syncRef.md +195 -0
- package/skills/vueuse-functions/references/syncRefs.md +128 -0
- package/skills/vueuse-functions/references/templateRef.md +86 -0
- package/skills/vueuse-functions/references/toObserver.md +38 -0
- package/skills/vueuse-functions/references/toReactive.md +41 -0
- package/skills/vueuse-functions/references/toRef.md +74 -0
- package/skills/vueuse-functions/references/toRefs.md +78 -0
- package/skills/vueuse-functions/references/tryOnBeforeMount.md +34 -0
- package/skills/vueuse-functions/references/tryOnBeforeUnmount.md +32 -0
- package/skills/vueuse-functions/references/tryOnMounted.md +34 -0
- package/skills/vueuse-functions/references/tryOnScopeDispose.md +31 -0
- package/skills/vueuse-functions/references/tryOnUnmounted.md +32 -0
- package/skills/vueuse-functions/references/unrefElement.md +54 -0
- package/skills/vueuse-functions/references/until.md +161 -0
- package/skills/vueuse-functions/references/useAbs.md +31 -0
- package/skills/vueuse-functions/references/useActiveElement.md +86 -0
- package/skills/vueuse-functions/references/useAnimate.md +180 -0
- package/skills/vueuse-functions/references/useArrayDifference.md +84 -0
- package/skills/vueuse-functions/references/useArrayEvery.md +59 -0
- package/skills/vueuse-functions/references/useArrayFilter.md +63 -0
- package/skills/vueuse-functions/references/useArrayFind.md +50 -0
- package/skills/vueuse-functions/references/useArrayFindIndex.md +59 -0
- package/skills/vueuse-functions/references/useArrayFindLast.md +52 -0
- package/skills/vueuse-functions/references/useArrayIncludes.md +63 -0
- package/skills/vueuse-functions/references/useArrayJoin.md +74 -0
- package/skills/vueuse-functions/references/useArrayMap.md +59 -0
- package/skills/vueuse-functions/references/useArrayReduce.md +81 -0
- package/skills/vueuse-functions/references/useArraySome.md +59 -0
- package/skills/vueuse-functions/references/useArrayUnique.md +76 -0
- package/skills/vueuse-functions/references/useAsyncQueue.md +136 -0
- package/skills/vueuse-functions/references/useAsyncState.md +185 -0
- package/skills/vueuse-functions/references/useAsyncValidator.md +70 -0
- package/skills/vueuse-functions/references/useAuth.md +123 -0
- package/skills/vueuse-functions/references/useAverage.md +36 -0
- package/skills/vueuse-functions/references/useAxios.md +325 -0
- package/skills/vueuse-functions/references/useBase64.md +136 -0
- package/skills/vueuse-functions/references/useBattery.md +80 -0
- package/skills/vueuse-functions/references/useBluetooth.md +174 -0
- package/skills/vueuse-functions/references/useBreakpoints.md +176 -0
- package/skills/vueuse-functions/references/useBroadcastChannel.md +73 -0
- package/skills/vueuse-functions/references/useBrowserLocation.md +56 -0
- package/skills/vueuse-functions/references/useCached.md +52 -0
- package/skills/vueuse-functions/references/useCeil.md +31 -0
- package/skills/vueuse-functions/references/useChangeCase.md +79 -0
- package/skills/vueuse-functions/references/useClamp.md +85 -0
- package/skills/vueuse-functions/references/useClipboard.md +122 -0
- package/skills/vueuse-functions/references/useClipboardItems.md +93 -0
- package/skills/vueuse-functions/references/useCloned.md +91 -0
- package/skills/vueuse-functions/references/useColorMode.md +172 -0
- package/skills/vueuse-functions/references/useConfirmDialog.md +159 -0
- package/skills/vueuse-functions/references/useCookies.md +162 -0
- package/skills/vueuse-functions/references/useCountdown.md +105 -0
- package/skills/vueuse-functions/references/useCounter.md +86 -0
- package/skills/vueuse-functions/references/useCssSupports.md +33 -0
- package/skills/vueuse-functions/references/useCssVar.md +50 -0
- package/skills/vueuse-functions/references/useCurrentElement.md +61 -0
- package/skills/vueuse-functions/references/useCycleList.md +75 -0
- package/skills/vueuse-functions/references/useDark.md +142 -0
- package/skills/vueuse-functions/references/useDateFormat.md +145 -0
- package/skills/vueuse-functions/references/useDebounceFn.md +100 -0
- package/skills/vueuse-functions/references/useDebouncedRefHistory.md +40 -0
- package/skills/vueuse-functions/references/useDeviceMotion.md +80 -0
- package/skills/vueuse-functions/references/useDeviceOrientation.md +64 -0
- package/skills/vueuse-functions/references/useDevicePixelRatio.md +47 -0
- package/skills/vueuse-functions/references/useDevicesList.md +89 -0
- package/skills/vueuse-functions/references/useDisplayMedia.md +67 -0
- package/skills/vueuse-functions/references/useDocumentVisibility.md +44 -0
- package/skills/vueuse-functions/references/useDraggable.md +289 -0
- package/skills/vueuse-functions/references/useDrauu.md +65 -0
- package/skills/vueuse-functions/references/useDropZone.md +83 -0
- package/skills/vueuse-functions/references/useElementBounding.md +131 -0
- package/skills/vueuse-functions/references/useElementByPoint.md +46 -0
- package/skills/vueuse-functions/references/useElementHover.md +79 -0
- package/skills/vueuse-functions/references/useElementSize.md +79 -0
- package/skills/vueuse-functions/references/useElementVisibility.md +163 -0
- package/skills/vueuse-functions/references/useEventBus.md +101 -0
- package/skills/vueuse-functions/references/useEventListener.md +226 -0
- package/skills/vueuse-functions/references/useEventSource.md +204 -0
- package/skills/vueuse-functions/references/useExtractedObservable.md +198 -0
- package/skills/vueuse-functions/references/useEyeDropper.md +72 -0
- package/skills/vueuse-functions/references/useFavicon.md +69 -0
- package/skills/vueuse-functions/references/useFetch.md +546 -0
- package/skills/vueuse-functions/references/useFileDialog.md +91 -0
- package/skills/vueuse-functions/references/useFileSystemAccess.md +161 -0
- package/skills/vueuse-functions/references/useFirestore.md +129 -0
- package/skills/vueuse-functions/references/useFloor.md +31 -0
- package/skills/vueuse-functions/references/useFocus.md +99 -0
- package/skills/vueuse-functions/references/useFocusTrap.md +245 -0
- package/skills/vueuse-functions/references/useFocusWithin.md +57 -0
- package/skills/vueuse-functions/references/useFps.md +28 -0
- package/skills/vueuse-functions/references/useFullscreen.md +74 -0
- package/skills/vueuse-functions/references/useFuse.md +75 -0
- package/skills/vueuse-functions/references/useGamepad.md +176 -0
- package/skills/vueuse-functions/references/useGeolocation.md +63 -0
- package/skills/vueuse-functions/references/useIDBKeyval.md +93 -0
- package/skills/vueuse-functions/references/useIdle.md +88 -0
- package/skills/vueuse-functions/references/useImage.md +90 -0
- package/skills/vueuse-functions/references/useInfiniteScroll.md +156 -0
- package/skills/vueuse-functions/references/useIntersectionObserver.md +117 -0
- package/skills/vueuse-functions/references/useInterval.md +112 -0
- package/skills/vueuse-functions/references/useIntervalFn.md +50 -0
- package/skills/vueuse-functions/references/useIpcRenderer.md +144 -0
- package/skills/vueuse-functions/references/useIpcRendererInvoke.md +58 -0
- package/skills/vueuse-functions/references/useIpcRendererOn.md +52 -0
- package/skills/vueuse-functions/references/useJwt.md +57 -0
- package/skills/vueuse-functions/references/useKeyModifier.md +87 -0
- package/skills/vueuse-functions/references/useLastChanged.md +63 -0
- package/skills/vueuse-functions/references/useLocalStorage.md +41 -0
- package/skills/vueuse-functions/references/useMagicKeys.md +245 -0
- package/skills/vueuse-functions/references/useManualRefHistory.md +204 -0
- package/skills/vueuse-functions/references/useMath.md +47 -0
- package/skills/vueuse-functions/references/useMax.md +36 -0
- package/skills/vueuse-functions/references/useMediaControls.md +201 -0
- package/skills/vueuse-functions/references/useMediaQuery.md +53 -0
- package/skills/vueuse-functions/references/useMemoize.md +175 -0
- package/skills/vueuse-functions/references/useMemory.md +70 -0
- package/skills/vueuse-functions/references/useMin.md +36 -0
- package/skills/vueuse-functions/references/useMounted.md +38 -0
- package/skills/vueuse-functions/references/useMouse.md +113 -0
- package/skills/vueuse-functions/references/useMouseInElement.md +132 -0
- package/skills/vueuse-functions/references/useMousePressed.md +116 -0
- package/skills/vueuse-functions/references/useMutationObserver.md +60 -0
- package/skills/vueuse-functions/references/useNProgress.md +78 -0
- package/skills/vueuse-functions/references/useNavigatorLanguage.md +57 -0
- package/skills/vueuse-functions/references/useNetwork.md +106 -0
- package/skills/vueuse-functions/references/useNow.md +83 -0
- package/skills/vueuse-functions/references/useObjectUrl.md +55 -0
- package/skills/vueuse-functions/references/useObservable.md +91 -0
- package/skills/vueuse-functions/references/useOffsetPagination.md +199 -0
- package/skills/vueuse-functions/references/useOnline.md +41 -0
- package/skills/vueuse-functions/references/usePageLeave.md +43 -0
- package/skills/vueuse-functions/references/useParallax.md +58 -0
- package/skills/vueuse-functions/references/useParentElement.md +54 -0
- package/skills/vueuse-functions/references/usePerformanceObserver.md +48 -0
- package/skills/vueuse-functions/references/usePermission.md +78 -0
- package/skills/vueuse-functions/references/usePointer.md +91 -0
- package/skills/vueuse-functions/references/usePointerLock.md +59 -0
- package/skills/vueuse-functions/references/usePointerSwipe.md +80 -0
- package/skills/vueuse-functions/references/usePrecision.md +49 -0
- package/skills/vueuse-functions/references/usePreferredColorScheme.md +42 -0
- package/skills/vueuse-functions/references/usePreferredContrast.md +42 -0
- package/skills/vueuse-functions/references/usePreferredDark.md +41 -0
- package/skills/vueuse-functions/references/usePreferredLanguages.md +41 -0
- package/skills/vueuse-functions/references/usePreferredReducedMotion.md +42 -0
- package/skills/vueuse-functions/references/usePreferredReducedTransparency.md +42 -0
- package/skills/vueuse-functions/references/usePrevious.md +40 -0
- package/skills/vueuse-functions/references/useProjection.md +38 -0
- package/skills/vueuse-functions/references/useQRCode.md +53 -0
- package/skills/vueuse-functions/references/useRTDB.md +83 -0
- package/skills/vueuse-functions/references/useRafFn.md +68 -0
- package/skills/vueuse-functions/references/useRefHistory.md +285 -0
- package/skills/vueuse-functions/references/useResizeObserver.md +108 -0
- package/skills/vueuse-functions/references/useRound.md +31 -0
- package/skills/vueuse-functions/references/useRouteHash.md +27 -0
- package/skills/vueuse-functions/references/useRouteParams.md +38 -0
- package/skills/vueuse-functions/references/useRouteQuery.md +79 -0
- package/skills/vueuse-functions/references/useSSRWidth.md +47 -0
- package/skills/vueuse-functions/references/useScreenOrientation.md +98 -0
- package/skills/vueuse-functions/references/useScreenSafeArea.md +60 -0
- package/skills/vueuse-functions/references/useScriptTag.md +116 -0
- package/skills/vueuse-functions/references/useScroll.md +238 -0
- package/skills/vueuse-functions/references/useScrollLock.md +66 -0
- package/skills/vueuse-functions/references/useSessionStorage.md +41 -0
- package/skills/vueuse-functions/references/useShare.md +67 -0
- package/skills/vueuse-functions/references/useSortable.md +276 -0
- package/skills/vueuse-functions/references/useSorted.md +90 -0
- package/skills/vueuse-functions/references/useSpeechRecognition.md +90 -0
- package/skills/vueuse-functions/references/useSpeechSynthesis.md +101 -0
- package/skills/vueuse-functions/references/useStepper.md +137 -0
- package/skills/vueuse-functions/references/useStorage.md +278 -0
- package/skills/vueuse-functions/references/useStorageAsync.md +136 -0
- package/skills/vueuse-functions/references/useStyleTag.md +131 -0
- package/skills/vueuse-functions/references/useSubject.md +77 -0
- package/skills/vueuse-functions/references/useSubscription.md +33 -0
- package/skills/vueuse-functions/references/useSum.md +36 -0
- package/skills/vueuse-functions/references/useSupported.md +29 -0
- package/skills/vueuse-functions/references/useSwipe.md +75 -0
- package/skills/vueuse-functions/references/useTemplateRefsList.md +37 -0
- package/skills/vueuse-functions/references/useTextDirection.md +75 -0
- package/skills/vueuse-functions/references/useTextSelection.md +43 -0
- package/skills/vueuse-functions/references/useTextareaAutosize.md +94 -0
- package/skills/vueuse-functions/references/useThrottleFn.md +57 -0
- package/skills/vueuse-functions/references/useThrottledRefHistory.md +47 -0
- package/skills/vueuse-functions/references/useTimeAgo.md +154 -0
- package/skills/vueuse-functions/references/useTimeAgoIntl.md +117 -0
- package/skills/vueuse-functions/references/useTimeout.md +113 -0
- package/skills/vueuse-functions/references/useTimeoutFn.md +51 -0
- package/skills/vueuse-functions/references/useTimeoutPoll.md +47 -0
- package/skills/vueuse-functions/references/useTimestamp.md +93 -0
- package/skills/vueuse-functions/references/useTitle.md +115 -0
- package/skills/vueuse-functions/references/useToNumber.md +54 -0
- package/skills/vueuse-functions/references/useToString.md +34 -0
- package/skills/vueuse-functions/references/useToggle.md +103 -0
- package/skills/vueuse-functions/references/useTransition.md +265 -0
- package/skills/vueuse-functions/references/useTrunc.md +33 -0
- package/skills/vueuse-functions/references/useUrlSearchParams.md +121 -0
- package/skills/vueuse-functions/references/useUserMedia.md +96 -0
- package/skills/vueuse-functions/references/useVModel.md +182 -0
- package/skills/vueuse-functions/references/useVModels.md +67 -0
- package/skills/vueuse-functions/references/useVibrate.md +86 -0
- package/skills/vueuse-functions/references/useVirtualList.md +182 -0
- package/skills/vueuse-functions/references/useWakeLock.md +51 -0
- package/skills/vueuse-functions/references/useWebNotification.md +175 -0
- package/skills/vueuse-functions/references/useWebSocket.md +299 -0
- package/skills/vueuse-functions/references/useWebWorker.md +60 -0
- package/skills/vueuse-functions/references/useWebWorkerFn.md +102 -0
- package/skills/vueuse-functions/references/useWindowFocus.md +46 -0
- package/skills/vueuse-functions/references/useWindowScroll.md +46 -0
- package/skills/vueuse-functions/references/useWindowSize.md +78 -0
- package/skills/vueuse-functions/references/useZoomFactor.md +53 -0
- package/skills/vueuse-functions/references/useZoomLevel.md +53 -0
- package/skills/vueuse-functions/references/watchArray.md +53 -0
- package/skills/vueuse-functions/references/watchAtMost.md +63 -0
- package/skills/vueuse-functions/references/watchDebounced.md +101 -0
- package/skills/vueuse-functions/references/watchDeep.md +54 -0
- package/skills/vueuse-functions/references/watchExtractedObservable.md +192 -0
- package/skills/vueuse-functions/references/watchIgnorable.md +120 -0
- package/skills/vueuse-functions/references/watchImmediate.md +44 -0
- package/skills/vueuse-functions/references/watchOnce.md +41 -0
- package/skills/vueuse-functions/references/watchPausable.md +86 -0
- package/skills/vueuse-functions/references/watchThrottled.md +108 -0
- package/skills/vueuse-functions/references/watchTriggerable.md +98 -0
- package/skills/vueuse-functions/references/watchWithFilter.md +54 -0
- package/skills/vueuse-functions/references/whenever.md +108 -0
- package/skills/web-design-guidelines/SKILL.md +39 -0
- package/skills/web-design-guidelines/SYNC.md +5 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: error-handling
|
|
3
|
+
description: Error handling patterns in Node.js
|
|
4
|
+
metadata:
|
|
5
|
+
tags: errors, exceptions, try-catch, error-handling
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Error Handling in Node.js
|
|
9
|
+
|
|
10
|
+
## Custom Errors with @fastify/create-error
|
|
11
|
+
|
|
12
|
+
Use [@fastify/create-error](https://github.com/fastify/fastify-error) for creating custom errors with codes:
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import createError from '@fastify/create-error';
|
|
16
|
+
|
|
17
|
+
const NotFoundError = createError('NOT_FOUND', '%s not found', 404);
|
|
18
|
+
const ValidationError = createError('VALIDATION_ERROR', '%s', 400);
|
|
19
|
+
const DatabaseError = createError('DATABASE_ERROR', 'Database operation failed: %s', 500);
|
|
20
|
+
|
|
21
|
+
// Usage
|
|
22
|
+
throw new NotFoundError('User');
|
|
23
|
+
throw new ValidationError('Email is required');
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Minimal Error Code Implementation
|
|
27
|
+
|
|
28
|
+
If you prefer no dependencies, use this minimal pattern:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
interface AppErrorOptions {
|
|
32
|
+
code: string;
|
|
33
|
+
statusCode?: number;
|
|
34
|
+
cause?: Error;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function createAppError(message: string, options: AppErrorOptions): Error {
|
|
38
|
+
const error = new Error(message, { cause: options.cause });
|
|
39
|
+
(error as any).code = options.code;
|
|
40
|
+
(error as any).statusCode = options.statusCode ?? 500;
|
|
41
|
+
Error.captureStackTrace(error, createAppError);
|
|
42
|
+
return error;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Factory functions for common errors
|
|
46
|
+
function notFound(resource: string): Error {
|
|
47
|
+
return createAppError(`${resource} not found`, { code: 'NOT_FOUND', statusCode: 404 });
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function validationError(message: string): Error {
|
|
51
|
+
return createAppError(message, { code: 'VALIDATION_ERROR', statusCode: 400 });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function databaseError(message: string, cause?: Error): Error {
|
|
55
|
+
return createAppError(message, { code: 'DATABASE_ERROR', statusCode: 500, cause });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Usage
|
|
59
|
+
throw notFound('User');
|
|
60
|
+
throw validationError('Email is required');
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Checking Error Codes
|
|
64
|
+
|
|
65
|
+
Check errors by code, not by class:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
function isAppError(error: unknown): error is Error & { code: string; statusCode: number } {
|
|
69
|
+
return error instanceof Error && 'code' in error && 'statusCode' in error;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
await fetchUser(id);
|
|
74
|
+
} catch (error) {
|
|
75
|
+
if (isAppError(error) && error.code === 'NOT_FOUND') {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Async Error Handling
|
|
83
|
+
|
|
84
|
+
Always use try-catch with async/await and propagate errors properly:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
async function fetchUser(id: string): Promise<User> {
|
|
88
|
+
try {
|
|
89
|
+
const user = await db.users.findById(id);
|
|
90
|
+
if (!user) {
|
|
91
|
+
throw notFound('User');
|
|
92
|
+
}
|
|
93
|
+
return user;
|
|
94
|
+
} catch (error) {
|
|
95
|
+
if (isAppError(error)) {
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
throw databaseError('Failed to fetch user', error as Error);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Unhandled Rejections and Exceptions
|
|
104
|
+
|
|
105
|
+
Do not handle `unhandledRejection` and `uncaughtException` manually. Use [close-with-grace](https://github.com/fastify/close-with-grace) which handles these automatically and triggers graceful shutdown.
|
|
106
|
+
|
|
107
|
+
See [graceful-shutdown.md](./graceful-shutdown.md) for proper shutdown handling.
|
|
108
|
+
|
|
109
|
+
## Fastify Error Handling
|
|
110
|
+
|
|
111
|
+
Fastify has built-in error handling:
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
import Fastify from 'fastify';
|
|
115
|
+
|
|
116
|
+
const app = Fastify({ logger: true });
|
|
117
|
+
|
|
118
|
+
app.setErrorHandler((error, request, reply) => {
|
|
119
|
+
const statusCode = (error as any).statusCode ?? 500;
|
|
120
|
+
const code = (error as any).code ?? 'INTERNAL_ERROR';
|
|
121
|
+
|
|
122
|
+
request.log.error(error);
|
|
123
|
+
|
|
124
|
+
reply.status(statusCode).send({
|
|
125
|
+
error: {
|
|
126
|
+
code,
|
|
127
|
+
message: error.message,
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Never Swallow Errors
|
|
134
|
+
|
|
135
|
+
Never use empty catch blocks that hide errors:
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
// BAD - error is swallowed
|
|
139
|
+
try {
|
|
140
|
+
await riskyOperation();
|
|
141
|
+
} catch (error) {
|
|
142
|
+
// Do nothing
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// GOOD - handle or re-throw
|
|
146
|
+
try {
|
|
147
|
+
await riskyOperation();
|
|
148
|
+
} catch (error) {
|
|
149
|
+
logger.error({ err: error }, 'Operation failed');
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Error Cause Chain
|
|
155
|
+
|
|
156
|
+
Use the `cause` option to preserve error chains:
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
try {
|
|
160
|
+
await externalService.call();
|
|
161
|
+
} catch (error) {
|
|
162
|
+
throw new Error('Service call failed', { cause: error });
|
|
163
|
+
}
|
|
164
|
+
```
|
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: flaky-tests
|
|
3
|
+
description: Identifying and diagnosing flaky tests with node:test
|
|
4
|
+
metadata:
|
|
5
|
+
tags: testing, flaky-tests, node-test, debugging, ci
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Identifying and Diagnosing Flaky Tests
|
|
9
|
+
|
|
10
|
+
Flaky tests are tests that pass or fail intermittently without code changes. They erode trust in the test suite and waste debugging time. This guide helps identify root causes and fix them.
|
|
11
|
+
|
|
12
|
+
## Identifying Which Test/File is Timing Out
|
|
13
|
+
|
|
14
|
+
When tests timeout, use these techniques to identify the culprit:
|
|
15
|
+
|
|
16
|
+
### 1. Use --test-reporter for Detailed Output
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Show each test as it runs (tap format shows test file and name)
|
|
20
|
+
node --test --test-reporter=tap
|
|
21
|
+
|
|
22
|
+
# Use spec reporter for hierarchical view
|
|
23
|
+
node --test --test-reporter=spec
|
|
24
|
+
|
|
25
|
+
# Run with verbose output to see which test hangs
|
|
26
|
+
node --test --test-reporter=spec 2>&1 | tee test-output.log
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 2. Run Tests with Timeout Tracking
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Set a global timeout and see which test exceeds it
|
|
33
|
+
node --test --test-timeout=5000
|
|
34
|
+
|
|
35
|
+
# The error message will include the test name and file:
|
|
36
|
+
# Error: test timed out after 5000ms
|
|
37
|
+
# at /path/to/test.ts:42:5
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 3. Run Individual Test Files
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Isolate by running files one at a time
|
|
44
|
+
for f in src/**/*.test.ts; do
|
|
45
|
+
echo "Running: $f"
|
|
46
|
+
timeout 30s node --test "$f" || echo "TIMEOUT or FAIL: $f"
|
|
47
|
+
done
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 4. Add Diagnostic Logging to Test Hooks
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { describe, it, before, after, beforeEach, afterEach } from 'node:test';
|
|
54
|
+
|
|
55
|
+
describe('MyTests', () => {
|
|
56
|
+
before(() => console.log('[BEFORE] MyTests starting'));
|
|
57
|
+
after(() => console.log('[AFTER] MyTests complete'));
|
|
58
|
+
beforeEach((t) => console.log(`[BEFORE EACH] Starting: ${t.name}`));
|
|
59
|
+
afterEach((t) => console.log(`[AFTER EACH] Finished: ${t.name}`));
|
|
60
|
+
|
|
61
|
+
it('test 1', () => { /* ... */ });
|
|
62
|
+
it('test 2', () => { /* ... */ });
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 5. Check for Hanging Async Operations
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Use --inspect to debug hanging tests
|
|
70
|
+
node --inspect --test src/hanging.test.ts
|
|
71
|
+
|
|
72
|
+
# Then connect Chrome DevTools to chrome://inspect
|
|
73
|
+
# Check the "Async" call stack to see what's pending
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 6. Use wtfnode to Find Open Handles
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { describe, it, after } from 'node:test';
|
|
80
|
+
import wtfnode from 'wtfnode';
|
|
81
|
+
|
|
82
|
+
describe('Debug hanging tests', () => {
|
|
83
|
+
after(() => {
|
|
84
|
+
// Dump what's keeping Node.js alive
|
|
85
|
+
wtfnode.dump();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('might hang', async () => {
|
|
89
|
+
// Your test
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Common Causes of Flaky Tests
|
|
95
|
+
|
|
96
|
+
### 1. Timing and Race Conditions
|
|
97
|
+
|
|
98
|
+
**Symptom**: Test passes locally but fails in CI, or fails randomly.
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
// BAD - Race condition with setTimeout
|
|
102
|
+
it('should process after delay', async (t) => {
|
|
103
|
+
let processed = false;
|
|
104
|
+
processAsync(() => { processed = true; });
|
|
105
|
+
|
|
106
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
107
|
+
t.assert.equal(processed, true); // May fail if processing takes > 100ms
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// GOOD - Wait for the actual condition
|
|
111
|
+
it('should process after delay', async (t) => {
|
|
112
|
+
const result = await processAsync();
|
|
113
|
+
t.assert.equal(result.processed, true);
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### 2. Uncontrolled Time Dependencies
|
|
118
|
+
|
|
119
|
+
**Symptom**: Tests fail around midnight, month boundaries, or in different timezones.
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
// BAD - Depends on current time
|
|
123
|
+
it('should format today', (t) => {
|
|
124
|
+
const result = formatDate(new Date());
|
|
125
|
+
t.assert.equal(result, '2024-01-15'); // Fails tomorrow
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// GOOD - Use fixed dates or mock time
|
|
129
|
+
it('should format date', (t) => {
|
|
130
|
+
const fixedDate = new Date('2024-01-15T12:00:00Z');
|
|
131
|
+
const result = formatDate(fixedDate);
|
|
132
|
+
t.assert.equal(result, '2024-01-15');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// GOOD - Mock Date with node:test
|
|
136
|
+
it('should format today', (t) => {
|
|
137
|
+
t.mock.timers.enable({ apis: ['Date'] });
|
|
138
|
+
t.mock.timers.setTime(new Date('2024-01-15T12:00:00Z').getTime());
|
|
139
|
+
|
|
140
|
+
const result = formatDate(new Date());
|
|
141
|
+
t.assert.equal(result, '2024-01-15');
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### 3. Port Conflicts
|
|
146
|
+
|
|
147
|
+
**Symptom**: "EADDRINUSE" errors, tests fail when run in parallel.
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
// BAD - Hardcoded port
|
|
151
|
+
it('should start server', async (t) => {
|
|
152
|
+
const server = await startServer({ port: 3000 }); // Conflicts with other tests
|
|
153
|
+
// ...
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// GOOD - Use dynamic port (port 0)
|
|
157
|
+
it('should start server', async (t) => {
|
|
158
|
+
const server = await startServer({ port: 0 });
|
|
159
|
+
const address = server.address();
|
|
160
|
+
const port = address.port; // OS assigns available port
|
|
161
|
+
// ...
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 4. Shared State Between Tests
|
|
166
|
+
|
|
167
|
+
**Symptom**: Tests pass individually but fail when run together.
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
// BAD - Module-level state persists between tests
|
|
171
|
+
let cache = new Map();
|
|
172
|
+
|
|
173
|
+
it('test 1', (t) => {
|
|
174
|
+
cache.set('key', 'value1');
|
|
175
|
+
t.assert.equal(cache.get('key'), 'value1');
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('test 2', (t) => {
|
|
179
|
+
t.assert.equal(cache.get('key'), undefined); // FAILS - still has 'value1'
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// GOOD - Reset state in beforeEach or use test-scoped state
|
|
183
|
+
describe('cache tests', () => {
|
|
184
|
+
let cache;
|
|
185
|
+
|
|
186
|
+
beforeEach(() => {
|
|
187
|
+
cache = new Map();
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('test 1', (t) => {
|
|
191
|
+
cache.set('key', 'value1');
|
|
192
|
+
t.assert.equal(cache.get('key'), 'value1');
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('test 2', (t) => {
|
|
196
|
+
t.assert.equal(cache.get('key'), undefined); // PASSES
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### 5. Test Order Dependencies
|
|
202
|
+
|
|
203
|
+
**Symptom**: Tests pass with `--test` but fail with `--test --parallel`.
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
// BAD - Test 2 depends on side effect from Test 1
|
|
207
|
+
it('test 1: create user', async (t) => {
|
|
208
|
+
await db.insert({ id: 1, name: 'John' });
|
|
209
|
+
t.assert.ok(true);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('test 2: find user', async (t) => {
|
|
213
|
+
const user = await db.findById(1); // Fails if test 1 didn't run first
|
|
214
|
+
t.assert.equal(user.name, 'John');
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// GOOD - Each test sets up its own data
|
|
218
|
+
it('test 2: find user', async (t) => {
|
|
219
|
+
await db.insert({ id: 1, name: 'John' }); // Setup within test
|
|
220
|
+
const user = await db.findById(1);
|
|
221
|
+
t.assert.equal(user.name, 'John');
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### 6. Unhandled Promise Rejections
|
|
226
|
+
|
|
227
|
+
**Symptom**: Test appears to pass but process exits with error, or random failures.
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
// BAD - Fire-and-forget async operation
|
|
231
|
+
it('should send notification', async (t) => {
|
|
232
|
+
sendNotification(user); // Not awaited - may reject after test ends
|
|
233
|
+
t.assert.ok(true);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// GOOD - Await all async operations
|
|
237
|
+
it('should send notification', async (t) => {
|
|
238
|
+
await sendNotification(user);
|
|
239
|
+
t.assert.ok(true);
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### 7. Resource Cleanup Failures
|
|
244
|
+
|
|
245
|
+
**Symptom**: Tests fail with "too many open files" or connections exhausted.
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
// BAD - Resources not cleaned up
|
|
249
|
+
it('should read file', async (t) => {
|
|
250
|
+
const handle = await fs.open('test.txt');
|
|
251
|
+
const content = await handle.read();
|
|
252
|
+
t.assert.ok(content);
|
|
253
|
+
// handle never closed!
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// GOOD - Always clean up resources
|
|
257
|
+
it('should read file', async (t) => {
|
|
258
|
+
const handle = await fs.open('test.txt');
|
|
259
|
+
t.after(() => handle.close()); // Cleanup registered
|
|
260
|
+
|
|
261
|
+
const content = await handle.read();
|
|
262
|
+
t.assert.ok(content);
|
|
263
|
+
});
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Debugging Strategies
|
|
267
|
+
|
|
268
|
+
### 1. Run Tests in Isolation
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
# Run single test file
|
|
272
|
+
node --test src/user.test.ts
|
|
273
|
+
|
|
274
|
+
# Run single test by name
|
|
275
|
+
node --test --test-name-pattern="should create user" src/user.test.ts
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### 2. Increase Concurrency to Expose Race Conditions
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
# Run with high concurrency to surface race conditions
|
|
282
|
+
node --test --test-concurrency=10
|
|
283
|
+
|
|
284
|
+
# Or run the same test multiple times
|
|
285
|
+
for i in {1..50}; do node --test src/flaky.test.ts || echo "Failed on run $i"; done
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### 3. Use Test Retry to Identify Flaky Tests
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
// Temporarily add retry to identify flaky test
|
|
292
|
+
it('potentially flaky test', { retry: 3 }, async (t) => {
|
|
293
|
+
// If this needs retries to pass, it's flaky
|
|
294
|
+
});
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### 4. Add Diagnostic Logging
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
it('flaky test', async (t) => {
|
|
301
|
+
console.log('Test started at:', Date.now());
|
|
302
|
+
console.log('Environment:', process.env.NODE_ENV);
|
|
303
|
+
|
|
304
|
+
const result = await operation();
|
|
305
|
+
console.log('Result:', JSON.stringify(result));
|
|
306
|
+
|
|
307
|
+
t.assert.ok(result);
|
|
308
|
+
});
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### 5. Check for Async Leaks
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
import { describe, it, after } from 'node:test';
|
|
315
|
+
|
|
316
|
+
describe('async leak detection', () => {
|
|
317
|
+
const activeHandles = new Set();
|
|
318
|
+
|
|
319
|
+
after(() => {
|
|
320
|
+
if (activeHandles.size > 0) {
|
|
321
|
+
console.error('Leaked handles:', [...activeHandles]);
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it('should not leak', async (t) => {
|
|
326
|
+
const timer = setTimeout(() => {}, 10000);
|
|
327
|
+
activeHandles.add(timer);
|
|
328
|
+
|
|
329
|
+
// Do test work...
|
|
330
|
+
|
|
331
|
+
clearTimeout(timer);
|
|
332
|
+
activeHandles.delete(timer);
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## Prevention Best Practices
|
|
338
|
+
|
|
339
|
+
### 1. Use Deterministic IDs
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
// BAD - Random IDs make debugging hard
|
|
343
|
+
const id = crypto.randomUUID();
|
|
344
|
+
|
|
345
|
+
// GOOD - Predictable IDs in tests
|
|
346
|
+
const id = `test-user-${t.name}`;
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### 2. Mock External Services
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
it('should fetch user', async (t) => {
|
|
353
|
+
// Mock fetch to avoid network flakiness
|
|
354
|
+
t.mock.method(globalThis, 'fetch', async () => ({
|
|
355
|
+
ok: true,
|
|
356
|
+
json: async () => ({ id: '1', name: 'John' }),
|
|
357
|
+
}));
|
|
358
|
+
|
|
359
|
+
const user = await fetchUser('1');
|
|
360
|
+
t.assert.equal(user.name, 'John');
|
|
361
|
+
});
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### 3. Use Explicit Waits Instead of Timeouts
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
// BAD - Arbitrary timeout
|
|
368
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
369
|
+
|
|
370
|
+
// GOOD - Wait for specific condition
|
|
371
|
+
await waitFor(() => element.isVisible());
|
|
372
|
+
|
|
373
|
+
// Helper function
|
|
374
|
+
async function waitFor(condition, timeout = 5000) {
|
|
375
|
+
const start = Date.now();
|
|
376
|
+
while (Date.now() - start < timeout) {
|
|
377
|
+
if (await condition()) return;
|
|
378
|
+
await new Promise(r => setTimeout(r, 50));
|
|
379
|
+
}
|
|
380
|
+
throw new Error('Condition not met within timeout');
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### 4. Ensure Test Isolation with Transactions
|
|
385
|
+
|
|
386
|
+
```typescript
|
|
387
|
+
describe('database tests', () => {
|
|
388
|
+
beforeEach(async () => {
|
|
389
|
+
await db.query('BEGIN');
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
afterEach(async () => {
|
|
393
|
+
await db.query('ROLLBACK');
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
it('should insert record', async (t) => {
|
|
397
|
+
await db.insert({ name: 'test' });
|
|
398
|
+
const records = await db.findAll();
|
|
399
|
+
t.assert.equal(records.length, 1);
|
|
400
|
+
});
|
|
401
|
+
});
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
## CI-Specific Flakiness
|
|
405
|
+
|
|
406
|
+
### 1. Resource Constraints
|
|
407
|
+
|
|
408
|
+
CI environments often have less CPU/memory. Add appropriate timeouts:
|
|
409
|
+
|
|
410
|
+
```typescript
|
|
411
|
+
it('heavy computation', { timeout: 30000 }, async (t) => {
|
|
412
|
+
// Longer timeout for CI
|
|
413
|
+
const result = await heavyOperation();
|
|
414
|
+
t.assert.ok(result);
|
|
415
|
+
});
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
### 2. Parallel Test Execution
|
|
419
|
+
|
|
420
|
+
Ensure tests don't conflict when run in parallel:
|
|
421
|
+
|
|
422
|
+
```bash
|
|
423
|
+
# In CI, run with controlled concurrency
|
|
424
|
+
node --test --test-concurrency=2
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### 3. Network Reliability
|
|
428
|
+
|
|
429
|
+
Mock external APIs in tests to avoid network-related flakiness:
|
|
430
|
+
|
|
431
|
+
```typescript
|
|
432
|
+
// Always mock external HTTP calls in unit tests
|
|
433
|
+
t.mock.method(globalThis, 'fetch', async (url) => {
|
|
434
|
+
if (url.includes('api.external.com')) {
|
|
435
|
+
return { ok: true, json: async () => mockData };
|
|
436
|
+
}
|
|
437
|
+
throw new Error(`Unmocked URL: ${url}`);
|
|
438
|
+
});
|
|
439
|
+
```
|