wallabyjs / public

Repository for Wallaby.js questions and issues
http://wallabyjs.com
757 stars 45 forks source link

Error: Could not find vendor entry #3166

Closed TeaBough closed 1 year ago

TeaBough commented 1 year ago

Issue description or question

I'm getting this when starting wallaby 👇 (I have a monorepo on pnpm workspace) Vitest 0.28.5 pnpm 7.27.0 node 16.13.0

0 failing tests, 0 passing Launch Coverage/Test Explorer

Failed to initialize wallaby vitest. Could not find vendor entry. Error: Could not find vendor entry.

Wallaby diagnostics report

{
  editorVersion: 'IntelliJ IDEA 2022.3.2',
  pluginVersion: '1.0.259',
  editorType: 'IntelliJ',
  osVersion: 'linux 5.17.15-76051715-generic',
  nodeVersion: 'v16.13.0',
  coreVersion: '1.0.1381',
  checksum: 'NjFjNGQ4NGNlZWE4Y2RlZmI0MWQwMWVhODdmMjcyNTUsMTcwMjA4MDAwMDAwMCww',
  config: {
    diagnostics: {
      vitest: {
        file: {
          config: '/// <reference types="vitest" />\n' +
            "import { defineConfig } from 'vite';\n" +
            "import tsconfigPaths from 'vite-tsconfig-paths';\n" +
            '// @ts-ignore\n' +
            "import svgrPlugin from 'vite-plugin-svgr';\n" +
            "import react from '@vitejs/plugin-react';\n" +
            '\n' +
            "const path = require('path');\n" +
            '\n' +
            '// https://vitejs.dev/config/\n' +
            'export default defineConfig({\n' +
            '  resolve: {\n' +
            '    alias: {\n' +
            "      'app': path.resolve(__dirname, './src'),\n" +
            "      '@tailwindConfig': path.resolve(__dirname, 'tailwind.config.js'),\n" +
            '    },\n' +
            '  },\n' +
            '  optimizeDeps: {\n' +
            "    include: ['@tailwindConfig'],\n" +
            '  },\n' +
            '  plugins: [\n' +
            '    react({\n' +
            '      babel: {\n' +
            "        plugins: ['twin', 'macros', 'styled-components'],\n" +
            '      },\n' +
            '    }),\n' +
            '    tsconfigPaths(),\n' +
            '    svgrPlugin(),\n' +
            '  ],\n' +
            '  server: {\n' +
            '    port: 9003,\n' +
            '  },\n' +
            '  test: {\n' +
            '    globals: true,\n' +
            "    environment: 'happy-dom',\n" +
            "    setupFiles: ['./src/testing/setupTests.ts'],\n" +
            '    exclude: [\n' +
            "      './e2e',\n" +
            "      '**/node_modules/**',\n" +
            "      '**/dist/**',\n" +
            "      '**/cypress/**',\n" +
            "      '**/.{idea,git,cache,output,temp}/**',\n" +
            "      '**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build}.config.*',\n" +
            '    ],\n' +
            '  },\n' +
            '});\n'
        },
        config: {
          allowOnly: true,
          watch: true,
          globals: true,
          environment: 'happy-dom',
          threads: true,
          clearMocks: false,
          restoreMocks: false,
          mockReset: false,
          include: [ '**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}' ],
          exclude: [
            './e2e',
            '**/node_modules/**',
            '**/dist/**',
            '**/cypress/**',
            '**/.{idea,git,cache,output,temp}/**',
            '**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build}.config.*'
          ],
          testTimeout: 5000,
          hookTimeout: 10000,
          teardownTimeout: 10000,
          isolate: true,
          watchExclude: [ '**/node_modules/**', '**/dist/**' ],
          forceRerunTriggers: [ '**/package.json/**', '**/{vitest,vite}.config.*/**', '<homeDir>/src/app/src/testing/setupTests.ts' ],
          update: false,
          reporters: [ 'default' ],
          silent: false,
          ui: false,
          uiBase: '/__vitest__/',
          open: true,
          css: { include: [], modules: { classNameStrategy: 'stable' } },
          coverage: {
            provider: 'c8',
            enabled: false,
            clean: true,
            cleanOnRerun: true,
            reportsDirectory: './coverage',
            exclude: [
              'coverage/**',
              'dist/**',
              'packages/*/test{,s}/**',
              '**/*.d.ts',
              'cypress/**',
              'test{,s}/**',
              'test{,-*}.{js,cjs,mjs,ts,tsx,jsx}',
              '**/*{.,-}test.{js,cjs,mjs,ts,tsx,jsx}',
              '**/*{.,-}spec.{js,cjs,mjs,ts,tsx,jsx}',
              '**/__tests__/**',
              '**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build}.config.*',
              '**/.{eslint,mocha,prettier}rc.{js,cjs,yml}',
              'src/testing/setupTests.ts'
            ],
            reporter: [ 'text', 'html', 'clover', 'json' ],
            extension: [
              '.js',  '.cjs',
              '.mjs', '.ts',
              '.mts', '.cts',
              '.tsx', '.jsx',
              '.vue', '.svelte'
            ]
          },
          fakeTimers: { loopLimit: 10000, shouldClearNativeTimers: true, toFake: [ 'setTimeout', 'clearTimeout', 'setInterval', 'clearInterval', 'setImmediate', 'clearImmediate', 'Date' ] },
          maxConcurrency: 5,
          dangerouslyIgnoreUnhandledErrors: false,
          typecheck: {
            checker: 'tsc',
            include: [ '**/*.{test,spec}-d.{ts,js}' ],
            exclude: [
              '**/node_modules/**',
              '**/dist/**',
              '**/cypress/**',
              '**/.{idea,git,cache,output,temp}/**',
              '**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build}.config.*'
            ]
          },
          slowTestThreshold: 300,
          setupFiles: [ '<homeDir>/src/testing/setupTests.ts' ],
          defines: {},
          root: '<homeDir>/src/app',
          mode: [],
          deps: { inline: [ {}, {}, {}, '@nuxt/test-utils' ], registerNodeLoader: false },
          snapshotOptions: { snapshotFormat: {}, updateSnapshot: 'new' },
          cache: { dir: '<homeDir>/src/app/node_modules/.vitest' },
          sequence: { hooks: 'parallel' },
          environmentMatchGlobs: [],
          package: {
            version: '0.28.5',
            urls: { hooks: 'file://<homeDir>/.cache/JetBrains/IntelliJIdea2022.3/wallaby/wallaby/runners/node/hooks.mjs' },
            paths: {
              root: '<homeDir>/src/node_modules/.pnpm/vitest@0.28.5_4gc7fp5kqndqxufgd3sbpcb2la/node_modules/vitest',
              dist: '<homeDir>/src/node_modules/.pnpm/vitest@0.28.5_4gc7fp5kqndqxufgd3sbpcb2la/node_modules/vitest/dist'
            }
          }
        }
      }
    },
    testFramework: { version: 'vitest@0.14.0', configurator: 'vitest@0.14.0', reporter: 'vitest@0.14.0', starter: 'vitest@0.14.0', autoDetected: true },
    preserveComments: false,
    extractComments: true,
    files: [
      { pattern: '**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}', ignore: true, trigger: true, load: true, file: true },
      { pattern: 'e2e', ignore: true, trigger: true, load: true, file: true },
      { pattern: '**/node_modules/**', ignore: true, trigger: true, load: true, file: true, test: true },
      { pattern: '**/dist/**', ignore: true, trigger: true, load: true, file: true, test: true },
      { pattern: '**/cypress/**', ignore: true, trigger: true, load: true, file: true, test: true },
      { pattern: '**/.{idea,git,cache,output,temp}/**', ignore: true, trigger: true, load: true, file: true, test: true },
      { pattern: '**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build}.config.*', ignore: true, trigger: true, load: true, file: true, test: true },
      { pattern: '**/*.*', ignore: false, trigger: true, load: true, order: 1 }
    ],
    tests: [
      { pattern: 'e2e', ignore: true, trigger: true, load: true, test: true, file: false },
      { pattern: '**/node_modules/**', ignore: true, trigger: true, load: true, test: true, file: false },
      { pattern: '**/dist/**', ignore: true, trigger: true, load: true, test: true, file: false },
      { pattern: '**/cypress/**', ignore: true, trigger: true, load: true, test: true, file: false },
      { pattern: '**/.{idea,git,cache,output,temp}/**', ignore: true, trigger: true, load: true, test: true, file: false },
      { pattern: '**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build}.config.*', ignore: true, trigger: true, load: true, test: true, file: false },
      { pattern: '**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}', ignore: false, trigger: true, load: true, test: true, order: 2 }
    ],
    workers: { initial: 1, regular: 1, recycle: false },
    filesWithNoCoverageCalculated: [],
    runAllTestsInAffectedTestFile: false,
    updateNoMoreThanOneSnapshotPerTestFileRun: false,
    compilers: {},
    logLimits: { inline: { depth: 5, elements: 5000 }, values: { default: { stringLength: 200 }, autoExpand: { elements: 5000, stringLength: 8192, depth: 10 } } },
    preprocessors: {},
    maxConsoleMessagesPerTest: 100,
    autoConsoleLog: true,
    delays: { run: 0, edit: 100, update: 0 },
    teardown: undefined,
    hints: {
      ignoreCoverage: '__REGEXP /ignore coverage|istanbul ignore/',
      ignoreCoverageForFile: '__REGEXP /ignore file coverage/',
      commentAutoLog: '?',
      testFileSelection: { include: '__REGEXP /file\\.only/', exclude: '__REGEXP /file\\.skip/' }
    },
    automaticTestFileSelection: true,
    runSelectedTestsOnly: false,
    mapConsoleMessagesStackTrace: false,
    extensions: {},
    env: {
      type: 'node',
      params: { runner: '--experimental-loader=file://<homeDir>/.cache/JetBrains/IntelliJIdea2022.3/wallaby/wallaby/runners/node/hooks.mjs' },
      runner: '<homeDir>/.nvm/versions/node/v16.13.0/bin/node',
      viewportSize: { width: 800, height: 600 },
      options: { width: 800, height: 600 },
      bundle: true
    },
    reportUnhandledPromises: true,
    slowTestThreshold: 75,
    lowCoverageThreshold: 80,
    runAllTestsWhenNoAffectedTests: true,
    symlinkNodeModules: undefined,
    configCode: 'auto.detect#-617391619'
  },
  packageJSON: {
    dependencies: {
      '@styled-icons/heroicons-outline': '=10.46.0',
      '@styled-icons/heroicons-solid': '=10.46.0',
      '@styled-icons/styled-icon': '=10.6.3',
      '@tanstack/query-core': '^4.24.6',
      '@tanstack/react-query': '^4.24.6',
      '@tanstack/react-query-devtools': '^4.24.6',
      '@tanstack/react-table': '^8.7.9',
      'babel-plugin-transform-object-rest-spread': '^6.26.0',
      'date-arithmetic': '^4.1.0',
      'file-saver': '^2.0.5',
      filesize: '^8.0.7',
      fontfaceobserver: '2.1.0',
      'hoist-non-react-statics': '3.3.2',
      jotai: '=1.13.1',
      'jotai-optics': '0.2.0',
      'jotai-tanstack-query': '^0.4.0',
      'js-cookie': '^3.0.1',
      'match-sorter': '^6.3.1',
      nanoid: '^3.1.22',
      'optics-ts': '^2.4.0',
      polished: '^4.1.2',
      qs: '^6.11.0',
      react: '^17.0.2',
      'react-app-polyfill': '3.0.0',
      'react-dom': '^17.0.2',
      'react-helmet-async': '1.3.0',
      'react-is': '^17.0.2',
      'react-router-dom': '6.8.1',
      'replace-in-file': '^6.3.5',
      'sanitize.css': '13.0.0',
      'shallow-equal': '^1.2.1',
      'styled-components': '5.3.5',
      uuid: '^8.3.2',
      validator: '^13.9.0',
      'workbox-window': '^6.5.4'
    },
    devDependencies: {
      '@babel/cli': '7.17.10',
      '@babel/core': '^7.20.12',
      '@babel/plugin-proposal-class-properties': '7.16.7',
      '@babel/plugin-proposal-nullish-coalescing-operator': '7.16.7',
      '@babel/plugin-proposal-optional-chaining': '7.16.7',
      '@babel/plugin-syntax-dynamic-import': '7.8.3',
      '@babel/plugin-transform-modules-commonjs': '7.17.9',
      '@babel/preset-env': '7.17.10',
      '@babel/preset-react': '7.18.6',
      '@babel/preset-typescript': '7.16.7',
      '@babel/register': '^7.18.9',
      '@hot-loader/react-dom': '17.0.2',
      '@playwright/test': '^1.30.0',
      '@popperjs/core': '^2.11.6',
      '@sentry/webpack-plugin': '^1.20.0',
      '@svgr/webpack': '^6.5.1',
      '@tailwindcss/forms': '^0.3.4',
      '@tailwindcss/typography': '^0.3.1',
      '@testing-library/dom': '9.0.0',
      '@testing-library/react': '12.1.5',
      '@testing-library/user-event': '^12.8.3',
      '@types/hoist-non-react-statics': '3.3.1',
      '@types/lodash': '4.14.182',
      '@types/lodash-es': '4.17.6',
      '@types/node': '16.18.12',
      '@types/react': '17.0.53',
      '@types/react-beautiful-dnd': '13.1.2',
      '@types/react-dom': '17.0.11',
      '@types/styled-components': '5.1.25',
      '@types/webpack': '5.28.0',
      '@types/webpack-env': '1.16.4',
      '@typescript-eslint/eslint-plugin': '5.52.0',
      '@typescript-eslint/parser': '5.52.0',
      '@vitejs/plugin-react': '^3.1.0',
      '@vitest/ui': 'latest',
      autoprefixer: '^10.4.13',
      'babel-loader': '8.2.5',
      'babel-plugin-dynamic-import-node': '2.3.3',
      'babel-plugin-preval': '^5.0.0',
      'babel-plugin-styled-components': '2.0.7',
      'babel-plugin-transform-react-remove-prop-types': '0.4.24',
      'babel-plugin-twin': '^1.1.0',
      'babel-preset-minify': '^0.5.2',
      chalk: '5.0.1',
      'circular-dependency-plugin': '5.2.2',
      'compare-versions': '4.1.3',
      compression: '1.7.4',
      'compression-webpack-plugin': '9.2.0',
      'cross-env': '7.0.3',
      'css-loader': '6.7.1',
      dotenv: '^16.0.3',
      'error-overlay-webpack-plugin': '1.1.0',
      eslint: '8.34.0',
      'eslint-config-airbnb-typescript': '17.0.0',
      'eslint-config-prettier': '8.5.0',
      'eslint-import-resolver-typescript': '3.5.3',
      'eslint-import-resolver-webpack': '0.13.2',
      'eslint-plugin-import': '2.27.5',
      'eslint-plugin-jsx-a11y': '6.7.1',
      'eslint-plugin-prettier': '4.2.1',
      'eslint-plugin-react': '7.32.2',
      'eslint-plugin-react-hooks': '4.6.0',
      'eslint-plugin-testing-library': '^5.10.2',
      esm: '3.2.25',
      express: '4.18.1',
      'extended-define-webpack-plugin': '^0.1.3',
      'file-loader': '6.2.0',
      'fork-ts-checker-webpack-plugin': '7.2.11',
      'happy-dom': '^8.4.3',
      'html-loader': '3.1.0',
      'html-webpack-plugin': '5.5.0',
      'imports-loader': '2.0.0',
      'intersection-observer': '^0.12.2',
      ip: '1.1.5',
      'lint-staged': '12.4.1',
      minifaker: '^1.33.1',
      minimist: '1.2.6',
      msw: '0.49.2',
      'node-plop': '0.31.0',
      'null-loader': '4.0.1',
      plop: '3.1.0',
      postcss: '^8.4.21',
      'postcss-loader': '^6.2.1',
      prettier: '^2.8.4',
      'prop-types': '^15.8.1',
      'react-input-autosize': '^3.0.0',
      'react-select-event': '^5.5.1',
      'react-sizeme': '^3.0.1',
      rimraf: '3.0.2',
      shelljs: '0.8.5',
      'style-loader': '3.3.1',
      'svg-url-loader': '7.1.1',
      tailwindcss: '2.2.19',
      'terser-webpack-plugin': '^5.3.6',
      'ts-loader': '9.3.0',
      typescript: '^4.9.5',
      'typescript-plugin-styled-components': '2.0.0',
      'url-loader': '4.1.1',
      'utility-types': '^3.10.0',
      vite: '^4.1.2',
      'vite-node': '^0.28.5',
      'vite-plugin-svgr': '^2.4.0',
      'vite-tsconfig-paths': '^4.0.5',
      vitest: '^0.28.5',
      webpack: '5.72.0',
      'webpack-bundle-analyzer': '^4.8.0',
      'webpack-cli': '^4.10.0',
      'webpack-dev-middleware': '5.3.1',
      'webpack-hot-middleware': '2.25.1',
      'webpack-nano': '1.1.1',
      'webpack-pwa-manifest': '4.3.0',
      'workbox-webpack-plugin': '^6.5.4'
    }
  },
  fs: { numberOfFiles: 6004 },
  debug: []
}
smcenlly commented 1 year ago

Unfortunately we could not reproduce your problem or identify why it's not working for you. We were using:

Vitest 0.28.5
pnpm 7.27.1
node 16.13.0

We created a sample repo with the same package dependencies listed in your diagnostics report. We also used almost identical vitest.config.ts (had to modify it very slightly because of some missing files). Could you please try this repo to confirm that it's working for you?

Can you please check/confirm that you have the file: node_modules/.pnpm/@vitest+runner@0.28.5/node_modules/@vitest/runner/dist/index.js? If so, can you please provide us with the contents of this file?


If our repo is working for you but your project is still having problems, then the cause is likely the structure of your mono-repo (e.g. where dependencies are located) or else you have a dependency mismatch somewhere (likely as a result of updating your dependencies over time).

Could you please try deleting your node_modules and pnpm-lock.yaml and then reinstall with pnpm install?

If you're still having problems, can you please try reproducing your configuring in our sample repo (or else create a new one) that has the same problem? After creating/updating the sample with the problem, please try cloning to a fresh directory and installing dependencies to ensure the problem can be reproduced.

TeaBough commented 1 year ago

We created a sample repo with the same package dependencies listed in your diagnostics report. We also used almost identical vitest.config.ts (had to modify it very slightly because of some missing files). Could you please try this repo to confirm that it's working for you?

It is working

Can you please check/confirm that you have the file: node_modules/.pnpm/@vitest+runner@0.28.5/node_modules/@vitest/runner/dist/index.js? If so, can you please provide us with the contents of this file?

I have this file hoisted in the node_modules folder in the root of the monorepo. Here is the content :

import limit from 'p-limit';
import { getSafeTimers, format, isObject, objDisplay, objectAttr, noop, toArray, shuffle } from '@vitest/utils';
import { c as createChainable, g as generateHash, p as processError, a as calculateSuiteHash, s as someTasksAreOnly, i as interpretTaskModes, b as partitionSuiteChildren, h as hasTests, d as hasFailed } from './chunk-tasks.js';
import { relative } from 'pathe';

const fnMap = /* @__PURE__ */ new WeakMap();
const hooksMap = /* @__PURE__ */ new WeakMap();
function setFn(key, fn) {
  fnMap.set(key, fn);
}
function getFn(key) {
  return fnMap.get(key);
}
function setHooks(key, hooks) {
  hooksMap.set(key, hooks);
}
function getHooks(key) {
  return hooksMap.get(key);
}

const collectorContext = {
  tasks: [],
  currentSuite: null
};
function collectTask(task) {
  var _a;
  (_a = collectorContext.currentSuite) == null ? void 0 : _a.tasks.push(task);
}
async function runWithSuite(suite, fn) {
  const prev = collectorContext.currentSuite;
  collectorContext.currentSuite = suite;
  await fn();
  collectorContext.currentSuite = prev;
}
function withTimeout(fn, timeout, isHook = false) {
  if (timeout <= 0 || timeout === Infinity)
    return fn;
  const { setTimeout, clearTimeout } = getSafeTimers();
  return (...args) => {
    return Promise.race([fn(...args), new Promise((resolve, reject) => {
      var _a;
      const timer = setTimeout(() => {
        clearTimeout(timer);
        reject(new Error(makeTimeoutMsg(isHook, timeout)));
      }, timeout);
      (_a = timer.unref) == null ? void 0 : _a.call(timer);
    })]);
  };
}
function createTestContext(test, runner) {
  var _a;
  const context = function() {
    throw new Error("done() callback is deprecated, use promise instead");
  };
  context.meta = test;
  context.onTestFailed = (fn) => {
    test.onFailed || (test.onFailed = []);
    test.onFailed.push(fn);
  };
  return ((_a = runner.extendTestContext) == null ? void 0 : _a.call(runner, context)) || context;
}
function makeTimeoutMsg(isHook, timeout) {
  return `${isHook ? "Hook" : "Test"} timed out in ${timeout}ms.
If this is a long-running ${isHook ? "hook" : "test"}, pass a timeout value as the last argument or configure it globally with "${isHook ? "hookTimeout" : "testTimeout"}".`;
}

const suite = createSuite();
const test = createTest(
  function(name, fn, options) {
    getCurrentSuite().test.fn.call(this, name, fn, options);
  }
);
const describe = suite;
const it = test;
let runner;
let defaultSuite;
function getDefaultSuite() {
  return defaultSuite;
}
function getRunner() {
  return runner;
}
function clearCollectorContext(currentRunner) {
  if (!defaultSuite)
    defaultSuite = currentRunner.config.sequence.shuffle ? suite.shuffle("") : suite("");
  runner = currentRunner;
  collectorContext.tasks.length = 0;
  defaultSuite.clear();
  collectorContext.currentSuite = defaultSuite;
}
function getCurrentSuite() {
  return collectorContext.currentSuite || defaultSuite;
}
function createSuiteHooks() {
  return {
    beforeAll: [],
    afterAll: [],
    beforeEach: [],
    afterEach: []
  };
}
function createSuiteCollector(name, factory = () => {
}, mode, concurrent, shuffle, suiteOptions) {
  const tasks = [];
  const factoryQueue = [];
  let suite2;
  initSuite();
  const test2 = createTest(function(name2, fn = noop, options = suiteOptions) {
    const mode2 = this.only ? "only" : this.skip ? "skip" : this.todo ? "todo" : "run";
    if (typeof options === "number")
      options = { timeout: options };
    const test3 = {
      id: "",
      type: "test",
      name: name2,
      mode: mode2,
      suite: void 0,
      fails: this.fails,
      retry: options == null ? void 0 : options.retry
    };
    if (this.concurrent || concurrent)
      test3.concurrent = true;
    if (shuffle)
      test3.shuffle = true;
    const context = createTestContext(test3, runner);
    Object.defineProperty(test3, "context", {
      value: context,
      enumerable: false
    });
    setFn(test3, withTimeout(
      () => fn(context),
      (options == null ? void 0 : options.timeout) ?? runner.config.testTimeout
    ));
    tasks.push(test3);
  });
  const custom = function(name2 = "") {
    const self = this || {};
    const task = {
      id: "",
      name: name2,
      type: "custom",
      mode: self.only ? "only" : self.skip ? "skip" : self.todo ? "todo" : "run"
    };
    tasks.push(task);
    return task;
  };
  const collector = {
    type: "collector",
    name,
    mode,
    test: test2,
    tasks,
    collect,
    custom,
    clear,
    on: addHook
  };
  function addHook(name2, ...fn) {
    getHooks(suite2)[name2].push(...fn);
  }
  function initSuite() {
    suite2 = {
      id: "",
      type: "suite",
      name,
      mode,
      shuffle,
      tasks: []
    };
    setHooks(suite2, createSuiteHooks());
  }
  function clear() {
    tasks.length = 0;
    factoryQueue.length = 0;
    initSuite();
  }
  async function collect(file) {
    factoryQueue.length = 0;
    if (factory)
      await runWithSuite(collector, () => factory(test2));
    const allChildren = [];
    for (const i of [...factoryQueue, ...tasks])
      allChildren.push(i.type === "collector" ? await i.collect(file) : i);
    suite2.file = file;
    suite2.tasks = allChildren;
    allChildren.forEach((task) => {
      task.suite = suite2;
      if (file)
        task.file = file;
    });
    return suite2;
  }
  collectTask(collector);
  return collector;
}
function createSuite() {
  function suiteFn(name, factory, options) {
    const mode = this.only ? "only" : this.skip ? "skip" : this.todo ? "todo" : "run";
    return createSuiteCollector(name, factory, mode, this.concurrent, this.shuffle, options);
  }
  suiteFn.each = function(cases, ...args) {
    const suite2 = this.withContext();
    if (Array.isArray(cases) && args.length)
      cases = formatTemplateString(cases, args);
    return (name, fn, options) => {
      const arrayOnlyCases = cases.every(Array.isArray);
      cases.forEach((i, idx) => {
        const items = Array.isArray(i) ? i : [i];
        arrayOnlyCases ? suite2(formatTitle(name, items, idx), () => fn(...items), options) : suite2(formatTitle(name, items, idx), () => fn(i), options);
      });
    };
  };
  suiteFn.skipIf = (condition) => condition ? suite.skip : suite;
  suiteFn.runIf = (condition) => condition ? suite : suite.skip;
  return createChainable(
    ["concurrent", "shuffle", "skip", "only", "todo"],
    suiteFn
  );
}
function createTest(fn) {
  const testFn = fn;
  testFn.each = function(cases, ...args) {
    const test2 = this.withContext();
    if (Array.isArray(cases) && args.length)
      cases = formatTemplateString(cases, args);
    return (name, fn2, options) => {
      const arrayOnlyCases = cases.every(Array.isArray);
      cases.forEach((i, idx) => {
        const items = Array.isArray(i) ? i : [i];
        arrayOnlyCases ? test2(formatTitle(name, items, idx), () => fn2(...items), options) : test2(formatTitle(name, items, idx), () => fn2(i), options);
      });
    };
  };
  testFn.skipIf = (condition) => condition ? test.skip : test;
  testFn.runIf = (condition) => condition ? test : test.skip;
  return createChainable(
    ["concurrent", "skip", "only", "todo", "fails"],
    testFn
  );
}
function formatTitle(template, items, idx) {
  if (template.includes("%#")) {
    template = template.replace(/%%/g, "__vitest_escaped_%__").replace(/%#/g, `${idx}`).replace(/__vitest_escaped_%__/g, "%%");
  }
  const count = template.split("%").length - 1;
  let formatted = format(template, ...items.slice(0, count));
  if (isObject(items[0])) {
    formatted = formatted.replace(
      /\$([$\w_.]+)/g,
      (_, key) => objDisplay(objectAttr(items[0], key))
    );
  }
  return formatted;
}
function formatTemplateString(cases, args) {
  const header = cases.join("").trim().replace(/ /g, "").split("\n").map((i) => i.split("|"))[0];
  const res = [];
  for (let i = 0; i < Math.floor(args.length / header.length); i++) {
    const oneCase = {};
    for (let j = 0; j < header.length; j++)
      oneCase[header[j]] = args[i * header.length + j];
    res.push(oneCase);
  }
  return res;
}

async function runSetupFiles(config, runner) {
  const files = toArray(config.setupFiles);
  await Promise.all(
    files.map(async (fsPath) => {
      await runner.importFile(fsPath, "setup");
    })
  );
}

const now$1 = Date.now;
async function collectTests(paths, runner) {
  const files = [];
  const config = runner.config;
  for (const filepath of paths) {
    const path = relative(config.root, filepath);
    const file = {
      id: generateHash(path),
      name: path,
      type: "suite",
      mode: "run",
      filepath,
      tasks: [],
      projectName: config.name
    };
    clearCollectorContext(runner);
    try {
      const setupStart = now$1();
      await runSetupFiles(config, runner);
      const collectStart = now$1();
      file.setupDuration = collectStart - setupStart;
      await runner.importFile(filepath, "collect");
      const defaultTasks = await getDefaultSuite().collect(file);
      setHooks(file, getHooks(defaultTasks));
      for (const c of [...defaultTasks.tasks, ...collectorContext.tasks]) {
        if (c.type === "test") {
          file.tasks.push(c);
        } else if (c.type === "custom") {
          file.tasks.push(c);
        } else if (c.type === "suite") {
          file.tasks.push(c);
        } else if (c.type === "collector") {
          const suite = await c.collect(file);
          if (suite.name || suite.tasks.length)
            file.tasks.push(suite);
        }
      }
      file.collectDuration = now$1() - collectStart;
    } catch (e) {
      const error = processError(e);
      file.result = {
        state: "fail",
        error,
        errors: [error]
      };
    }
    calculateSuiteHash(file);
    const hasOnlyTasks = someTasksAreOnly(file);
    interpretTaskModes(file, config.testNamePattern, hasOnlyTasks, false, config.allowOnly);
    files.push(file);
  }
  return files;
}

let _test;
function setCurrentTest(test) {
  _test = test;
}
function getCurrentTest() {
  return _test;
}

const now = Date.now;
function updateSuiteHookState(suite, name, state, runner) {
  var _a;
  if (!suite.result)
    suite.result = { state: "run" };
  if (!((_a = suite.result) == null ? void 0 : _a.hooks))
    suite.result.hooks = {};
  const suiteHooks = suite.result.hooks;
  if (suiteHooks) {
    suiteHooks[name] = state;
    updateTask(suite, runner);
  }
}
function getSuiteHooks(suite, name, sequence) {
  const hooks = getHooks(suite)[name];
  if (sequence === "stack" && (name === "afterAll" || name === "afterEach"))
    return hooks.slice().reverse();
  return hooks;
}
async function callSuiteHook(suite, currentTask, name, runner, args) {
  const sequence = runner.config.sequence.hooks;
  const callbacks = [];
  if (name === "beforeEach" && suite.suite) {
    callbacks.push(
      ...await callSuiteHook(suite.suite, currentTask, name, runner, args)
    );
  }
  updateSuiteHookState(currentTask, name, "run", runner);
  const hooks = getSuiteHooks(suite, name, sequence);
  if (sequence === "parallel") {
    callbacks.push(...await Promise.all(hooks.map((fn) => fn(...args))));
  } else {
    for (const hook of hooks)
      callbacks.push(await hook(...args));
  }
  updateSuiteHookState(currentTask, name, "pass", runner);
  if (name === "afterEach" && suite.suite) {
    callbacks.push(
      ...await callSuiteHook(suite.suite, currentTask, name, runner, args)
    );
  }
  return callbacks;
}
const packs = /* @__PURE__ */ new Map();
let updateTimer;
let previousUpdate;
function updateTask(task, runner) {
  packs.set(task.id, task.result);
  const { clearTimeout, setTimeout } = getSafeTimers();
  clearTimeout(updateTimer);
  updateTimer = setTimeout(() => {
    previousUpdate = sendTasksUpdate(runner);
  }, 10);
}
async function sendTasksUpdate(runner) {
  var _a;
  const { clearTimeout } = getSafeTimers();
  clearTimeout(updateTimer);
  await previousUpdate;
  if (packs.size) {
    const p = (_a = runner.onTaskUpdate) == null ? void 0 : _a.call(runner, Array.from(packs));
    packs.clear();
    return p;
  }
}
const callCleanupHooks = async (cleanups) => {
  await Promise.all(cleanups.map(async (fn) => {
    if (typeof fn !== "function")
      return;
    await fn();
  }));
};
async function runTest(test, runner) {
  var _a, _b, _c, _d, _e, _f;
  await ((_a = runner.onBeforeRunTest) == null ? void 0 : _a.call(runner, test));
  if (test.mode !== "run")
    return;
  if (((_b = test.result) == null ? void 0 : _b.state) === "fail") {
    updateTask(test, runner);
    return;
  }
  const start = now();
  test.result = {
    state: "run",
    startTime: start
  };
  updateTask(test, runner);
  setCurrentTest(test);
  const retry = test.retry || 1;
  for (let retryCount = 0; retryCount < retry; retryCount++) {
    let beforeEachCleanups = [];
    try {
      await ((_c = runner.onBeforeTryTest) == null ? void 0 : _c.call(runner, test, retryCount));
      beforeEachCleanups = await callSuiteHook(test.suite, test, "beforeEach", runner, [test.context, test.suite]);
      test.result.retryCount = retryCount;
      if (runner.runTest) {
        await runner.runTest(test);
      } else {
        const fn = getFn(test);
        if (!fn)
          throw new Error("Test function is not found. Did you add it using `setFn`?");
        await fn();
      }
      await ((_d = runner.onAfterTryTest) == null ? void 0 : _d.call(runner, test, retryCount));
      test.result.state = "pass";
    } catch (e) {
      failTask(test.result, e);
    }
    try {
      await callSuiteHook(test.suite, test, "afterEach", runner, [test.context, test.suite]);
      await callCleanupHooks(beforeEachCleanups);
    } catch (e) {
      failTask(test.result, e);
    }
    if (test.result.state === "pass")
      break;
    updateTask(test, runner);
  }
  if (test.result.state === "fail")
    await Promise.all(((_e = test.onFailed) == null ? void 0 : _e.map((fn) => fn(test.result))) || []);
  if (test.fails) {
    if (test.result.state === "pass") {
      const error = processError(new Error("Expect test to fail"));
      test.result.state = "fail";
      test.result.error = error;
      test.result.errors = [error];
    } else {
      test.result.state = "pass";
      test.result.error = void 0;
      test.result.errors = void 0;
    }
  }
  setCurrentTest(void 0);
  test.result.duration = now() - start;
  await ((_f = runner.onAfterRunTest) == null ? void 0 : _f.call(runner, test));
  updateTask(test, runner);
}
function failTask(result, err) {
  result.state = "fail";
  const error = processError(err);
  result.error = error;
  result.errors ?? (result.errors = []);
  result.errors.push(error);
}
function markTasksAsSkipped(suite, runner) {
  suite.tasks.forEach((t) => {
    t.mode = "skip";
    t.result = { ...t.result, state: "skip" };
    updateTask(t, runner);
    if (t.type === "suite")
      markTasksAsSkipped(t, runner);
  });
}
async function runSuite(suite, runner) {
  var _a, _b, _c;
  await ((_a = runner.onBeforeRunSuite) == null ? void 0 : _a.call(runner, suite));
  if (((_b = suite.result) == null ? void 0 : _b.state) === "fail") {
    markTasksAsSkipped(suite, runner);
    updateTask(suite, runner);
    return;
  }
  const start = now();
  suite.result = {
    state: "run",
    startTime: start
  };
  updateTask(suite, runner);
  let beforeAllCleanups = [];
  if (suite.mode === "skip") {
    suite.result.state = "skip";
  } else if (suite.mode === "todo") {
    suite.result.state = "todo";
  } else {
    try {
      beforeAllCleanups = await callSuiteHook(suite, suite, "beforeAll", runner, [suite]);
      if (runner.runSuite) {
        await runner.runSuite(suite);
      } else {
        for (let tasksGroup of partitionSuiteChildren(suite)) {
          if (tasksGroup[0].concurrent === true) {
            const mutex = limit(runner.config.maxConcurrency);
            await Promise.all(tasksGroup.map((c) => mutex(() => runSuiteChild(c, runner))));
          } else {
            const { sequence } = runner.config;
            if (sequence.shuffle || suite.shuffle) {
              const suites = tasksGroup.filter((group) => group.type === "suite");
              const tests = tasksGroup.filter((group) => group.type === "test");
              const groups = shuffle([suites, tests], sequence.seed);
              tasksGroup = groups.flatMap((group) => shuffle(group, sequence.seed));
            }
            for (const c of tasksGroup)
              await runSuiteChild(c, runner);
          }
        }
      }
    } catch (e) {
      failTask(suite.result, e);
    }
    try {
      await callSuiteHook(suite, suite, "afterAll", runner, [suite]);
      await callCleanupHooks(beforeAllCleanups);
    } catch (e) {
      failTask(suite.result, e);
    }
  }
  suite.result.duration = now() - start;
  if (suite.mode === "run") {
    if (!hasTests(suite)) {
      suite.result.state = "fail";
      if (!suite.result.error) {
        const error = processError(new Error(`No test found in suite ${suite.name}`));
        suite.result.error = error;
        suite.result.errors = [error];
      }
    } else if (hasFailed(suite)) {
      suite.result.state = "fail";
    } else {
      suite.result.state = "pass";
    }
  }
  await ((_c = runner.onAfterRunSuite) == null ? void 0 : _c.call(runner, suite));
  updateTask(suite, runner);
}
async function runSuiteChild(c, runner) {
  if (c.type === "test")
    return runTest(c, runner);
  else if (c.type === "suite")
    return runSuite(c, runner);
}
async function runFiles(files, runner) {
  var _a, _b;
  for (const file of files) {
    if (!file.tasks.length && !runner.config.passWithNoTests) {
      if (!((_b = (_a = file.result) == null ? void 0 : _a.errors) == null ? void 0 : _b.length)) {
        const error = processError(new Error(`No test suite found in file ${file.filepath}`));
        file.result = {
          state: "fail",
          error,
          errors: [error]
        };
      }
    }
    await runSuite(file, runner);
  }
}
async function startTests(paths, runner) {
  var _a, _b, _c, _d;
  await ((_a = runner.onBeforeCollect) == null ? void 0 : _a.call(runner, paths));
  const files = await collectTests(paths, runner);
  (_b = runner.onCollected) == null ? void 0 : _b.call(runner, files);
  await ((_c = runner.onBeforeRun) == null ? void 0 : _c.call(runner, files));
  await runFiles(files, runner);
  await ((_d = runner.onAfterRun) == null ? void 0 : _d.call(runner, files));
  await sendTasksUpdate(runner);
  return files;
}

const getDefaultHookTimeout = () => getRunner().config.hookTimeout;
const beforeAll = (fn, timeout) => getCurrentSuite().on("beforeAll", withTimeout(fn, timeout ?? getDefaultHookTimeout(), true));
const afterAll = (fn, timeout) => getCurrentSuite().on("afterAll", withTimeout(fn, timeout ?? getDefaultHookTimeout(), true));
const beforeEach = (fn, timeout) => getCurrentSuite().on("beforeEach", withTimeout(fn, timeout ?? getDefaultHookTimeout(), true));
const afterEach = (fn, timeout) => getCurrentSuite().on("afterEach", withTimeout(fn, timeout ?? getDefaultHookTimeout(), true));
const onTestFailed = createTestHook("onTestFailed", (test, handler) => {
  test.onFailed || (test.onFailed = []);
  test.onFailed.push(handler);
});
function createTestHook(name, handler) {
  return (fn) => {
    const current = getCurrentTest();
    if (!current)
      throw new Error(`Hook ${name}() can only be called inside a test`);
    handler(current, fn);
  };
}

export { afterAll, afterEach, beforeAll, beforeEach, describe, getCurrentSuite, getFn, it, onTestFailed, setFn, startTests, suite, test, updateTask };

Could you please try deleting your node_modules and pnpm-lock.yaml and then reinstall with pnpm install?

Still not working 😥

If you're still having problems, can you please try reproducing your configuring in our sample repo (or else create a new one) that has the same problem? After creating/updating the sample with the problem, please try cloning to a fresh directory and installing dependencies to ensure the problem can be reproduced.

Will do that 👍

TeaBough commented 1 year ago

Here is the repo that reproduce the problem : https://github.com/TeaBough/wallaby-2eset I think that the problem comes from the fact that vitest is hoisted, will try to do something about it...

smcenlly commented 1 year ago

Thanks for the sample repo. You are right, the problem in your case is that vitest and some of its dependencies are being hoisted but in your case, @vitest/runner wasn't being correctly hoisted in your project for Wallaby to use.

If you add @vitest/runner to your app/package.json it should fix the problem for you (it worked for us):

app/package.json

{
...
  "devDependencies": {
    "@vitest/ui": "^0.28.5",
+   "@vitest/runner": "^0.28.5",
    "autoprefixer": "^10.4.13",
...
  }
}

You will need to run pnpm install from your project root after making this change.

TeaBough commented 1 year ago

Yep it's working 🎉 Thank you @smcenlly 👌