quasarframework / quasar-testing

Testing Harness App Extensions for the Quasar Framework 2.0+
https://testing.quasar.dev
MIT License
180 stars 65 forks source link

Test suite failed to run. RangeError: Maximum call stack size exceeded, when trying to unit test a component. #191

Closed ZaeemKhaliq closed 2 years ago

ZaeemKhaliq commented 2 years ago

I am doing a really simple unit test of a component of my app. In the component, I have imported an icon from quasar (QIcon) as :-

//Cards.vue -> Component name import { outlinedPlayArrow } from "@quasar/extras/material-icons-outlined";

I am running the test with npm run test:unit

When I ran the test initially, I was getting the following error:-

Jest encountered an unexpected token

This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.

    By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".

    Here's what you can do:
     • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/en/ecmascript-modules for how to enable it.
     • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
     • If you need a custom transformation specify a "transform" option in your config.
     • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

    You'll find more details and examples of these config options in the docs:
    https://jestjs.io/docs/en/configuration.html

 SyntaxError: Unexpected token 'export'

      67 | <script>
      68 | import { mapState, mapGetters } from "vuex";
    > 69 | import { outlinedPlayArrow } from "@quasar/extras/material-icons-outlined";
         | ^
      70 |
      71 | export default {
      72 |   name: "Cards",

      at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1350:14)
      at Object.<anonymous> (src/components/Home/Body/Cards.vue:69:1)

I researched a bit and some answer said to include the @quasar folder in node_modules in the 'transformIgnorePatterns' property of jest config in order to not ignore the transformations for quasar extras. So I did this:-

const esModules = ["quasar/lang", "lodash-es", "@quasar/*"].join("|");
transformIgnorePatterns: [`node_modules/(?!(${esModules}))`],

But now it's giving this error: -

Test suite failed to run

RangeError: Maximum call stack size exceeded

      67 | <script>
      68 | import { mapState, mapGetters } from "vuex";
    > 69 | import { outlinedPlayArrow } from "@quasar/extras/material-icons-outlined";
         | ^
      70 |
      71 | export default {
      72 |   name: "Cards",

      at Runtime._execModule (node_modules/jest-runtime/build/index.js:1299:24)
      at Object.<anonymous> (src/components/Home/Body/Cards.vue:69:1)
      at Object.<anonymous> (test/jest/__tests__/Home/Cards.spec.js:8:1)

Please help me why is this problem occurring?

I am doing this simple test:-

/* eslint-disable no-unused-vars */
/* eslint-disable import/no-extraneous-dependencies */

import { describe, expect, it } from "@jest/globals";
import { installQuasarPlugin } from "@quasar/quasar-app-extension-testing-unit-jest";
import { mount, shallowMount } from "@vue/test-utils";

import Cards from "../../../../src/components/Home/Body/Cards.vue";

installQuasarPlugin();

describe("Cards", () => {
  it("Should render a value", async () => {
    const wrapper = mount(Cards);

    const value = wrapper.find(".value");

    expect(value.text()).toBeTruthy();
  });
});

My jest.config.js file:-

const esModules = ["quasar/lang", "lodash-es", "@quasar", "@quasar/*"].join(
  "|"
);

module.exports = {
  globals: {
    __DEV__: true,
    // TODO: Remove if resolved natively
    // See https://github.com/vuejs/vue-jest/issues/175
    "vue-jest": {
      pug: { doctype: "html" },
    },
  },
  // noStackTrace: true,
  // bail: true,
  // cache: false,
  // verbose: true,
  // watch: true,
  collectCoverage: false,
  coverageDirectory: "<rootDir>/test/jest/coverage",
  collectCoverageFrom: [
    "<rootDir>/src/**/*.vue",
    "<rootDir>/src/**/*.js",
    "<rootDir>/src/**/*.jsx",
  ],
  // Needed in JS codebases too because of feature flags
  coveragePathIgnorePatterns: ["/node_modules/", ".d.ts$"],
  coverageThreshold: {
    global: {
      //  branches: 50,
      //  functions: 50,
      //  lines: 50,
      //  statements: 50
    },
  },
  testMatch: [
    "<rootDir>/test/jest/__tests__/**/*.(spec|test).js",
    "<rootDir>/src/**/*.jest.(spec|test).js",
  ],
  moduleFileExtensions: ["vue", "js", "jsx", "json"],
  moduleNameMapper: {
    "^~/(.*)$": "<rootDir>/$1",
    "^src/(.*)$": "<rootDir>/src/$1",
    "^app/(.*)$": "<rootDir>/$1",
    "^components/(.*)$": "<rootDir>/src/components/$1",
    "^layouts/(.*)$": "<rootDir>/src/layouts/$1",
    "^pages/(.*)$": "<rootDir>/src/pages/$1",
    "^assets/(.*)$": "<rootDir>/src/assets/$1",
    "^boot/(.*)$": "<rootDir>/src/boot/$1",
    ".*css$": "@quasar/quasar-app-extension-testing-unit-jest/stub.css",
  },
  transform: {
    ".*\\.vue$": "vue-jest",
    ".*\\.js$": "babel-jest",
    ".+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$":
      "jest-transform-stub",
    // use these if NPM is being flaky, care as hosting could interfere with these
    // '.*\\.vue$': '@quasar/quasar-app-extension-testing-unit-jest/node_modules/vue-jest',
    // '.*\\.js$': '@quasar/quasar-app-extension-testing-unit-jest/node_modules/babel-jest'
  },
  transformIgnorePatterns: [`node_modules/(?!(${esModules}))`],
  snapshotSerializers: ["jest-serializer-vue"],
};

The babel.config.js file:-

/* eslint-env node */
// eslint-disable-next-line @typescript-eslint/no-var-requires
const fs = require('fs-extra');
let extend = undefined;

/**
 * The .babelrc file has been created to assist Jest for transpiling.
 * You should keep your application's babel rules in this file.
 */

if (fs.existsSync('./.babelrc')) {
  extend = './.babelrc';
}

module.exports = {
  presets: ['@quasar/babel-preset-app'],
  extends: extend,
};

The babel.rc file:-

{
  "plugins": ["@babel/plugin-syntax-dynamic-import"],
  "env": {
    "test": {
      "plugins": ["dynamic-import-node"],
      "presets": [
        [
          "@babel/preset-env",
          {
            "modules": "commonjs",
            "targets": {
              "node": "current"
            }
          }
        ]
      ]
    }
  }
}

And my package.json:-

{
  "scripts": {
    "lint": "eslint --ext .js,.vue ./",
    "test": "echo \"See package.json => scripts for available tests.\" && exit 0",
    "test:unit:ui": "majestic",
    "test:unit": "jest --updateSnapshot",
    "test:unit:ci": "jest --ci",
    "test:unit:coverage": "jest --coverage",
    "test:unit:watch": "jest --watch",
    "test:unit:watchAll": "jest --watchAll",
    "serve:test:coverage": "quasar serve test/jest/coverage/lcov-report/ --port 8788",
    "concurrently:dev:jest": "concurrently \"quasar dev\" \"jest --watch\""
  },
  "dependencies": {
    "@quasar/extras": "^1.0.0",
    "core-js": "^3.6.5",
    "gsap": "^3.8.0",
    "quasar": "^2.0.0",
    "vue": "^3.2.22",
    "vuex": "^4.0.1"
  },
  "devDependencies": {
    "@babel/eslint-parser": "^7.13.14",
    "@quasar/app": "^3.0.0",
    "@quasar/quasar-app-extension-testing-unit-jest": "^3.0.0-alpha.6",
    "eslint": "^7.14.0",
    "eslint-config-airbnb-base": "^14.0.0",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-import": "^2.20.1",
    "eslint-plugin-jest": "^25.2.2",
    "eslint-plugin-vue": "^7.0.0",
    "eslint-webpack-plugin": "^2.4.0",
    "majestic": "^1.7.0",
    "sass-loader": "^12.3.0"
  },
  "browserslist": [
    "last 10 Chrome versions",
    "last 10 Firefox versions",
    "last 4 Edge versions",
    "last 7 Safari versions",
    "last 8 Android versions",
    "last 8 ChromeAndroid versions",
    "last 8 FirefoxAndroid versions",
    "last 10 iOS versions",
    "last 5 Opera versions"
  ],
  "engines": {
    "node": ">= 12.22.1",
    "npm": ">= 6.13.4",
    "yarn": ">= 1.21.1"
  }
}
IlCallo commented 2 years ago

Try adding @quasar/extras into esModules instead of the whole @quasar/* If this doesn't work, can you create a repro? With the minimum amount of code to reproduce the error

IlCallo commented 2 years ago

Closing due to inactivity, please provide a repro if you want us to check out what's your problem

ZaeemKhaliq commented 2 years ago

Closing due to inactivity, please provide a repro if you want us to check out what's your problem

I am trying to reproduce the code on a simple new project. For that I am trying to install quasar-testing extension with this command: -

quasar ext add @quasar/testing

And now its not even installing the extension and giving the following error: -

(node:23776) UnhandledPromiseRejectionWarning:   Error: Cannot find module '@quasar/quasar-app-extension-testing/package.json'
  Require stack:
  - D:\VueProjects\QuasarProjects\sample\node_modules\@quasar\app\lib\app-extension\Extension.js   
  - D:\VueProjects\QuasarProjects\sample\node_modules\@quasar\app\bin\quasar-ext
  - D:\VueProjects\QuasarProjects\sample\node_modules\@quasar\app\bin\quasar
  - C:\Users\khali\AppData\Roaming\npm\node_modules\@quasar\cli\bin\quasar

  - loader.js:885 Function.Module._resolveFilename
    internal/modules/cjs/loader.js:885:15

  - helpers.js:94 Function.resolve
    internal/modules/cjs/helpers.js:94:19

  - Extension.js:310 Extension.__getPkgSrc
    [sample]/[@quasar]/app/lib/app-extension/Extension.js:310:25

  - Extension.js:318 Extension.__getScript
    [sample]/[@quasar]/app/lib/app-extension/Extension.js:318:25

  - Extension.js:262 Extension.__getPrompts
    [sample]/[@quasar]/app/lib/app-extension/Extension.js:262:28

  - Extension.js:178 Extension.install
    [sample]/[@quasar]/app/lib/app-extension/Extension.js:178:32

  - quasar-ext:63 run
    [sample]/[@quasar]/app/bin/quasar-ext:63:6

  - quasar-ext:80 Object.<anonymous>
    [sample]/[@quasar]/app/bin/quasar-ext:80:3

  - loader.js:1068 Module._compile
    internal/modules/cjs/loader.js:1068:30

  - loader.js:1097 Object.Module._extensions..js
    internal/modules/cjs/loader.js:1097:10

(Use `node --trace-warnings ...` to show where the warning was created)
(node:23776) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use 
the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
(node:23776) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Also tried installing it with: -

quasar ext add @quasar/testing-unit-jest

Still getting same error

Here is the package.json file: -

{
  "name": "sample",
  "version": "0.0.1",
  "description": "A Quasar Framework app",
  "productName": "Quasar App",
  "author": "Muhammad Zaeem Khaliq <khaliqzaeem@hotmail.com>",
  "private": true,
  "scripts": {
    "lint": "eslint --ext .js,.vue ./",
    "test": "echo \"No test specified\" && exit 0"
  },
  "dependencies": {
    "@quasar/extras": "^1.0.0",
    "axios": "^0.21.1",
    "core-js": "^3.6.5",
    "quasar": "^2.0.0",
    "vuex": "^4.0.1"
  },
  "devDependencies": {
    "@babel/eslint-parser": "^7.13.14",
    "@quasar/app": "^3.0.0",
    "@quasar/quasar-app-extension-testing": "^2.0.2",
    "eslint": "^7.14.0",
    "eslint-config-prettier": "^8.1.0",
    "eslint-plugin-vue": "^7.0.0",
    "eslint-webpack-plugin": "^2.4.0"
  },
  "browserslist": [
    "last 10 Chrome versions",
    "last 10 Firefox versions",
    "last 4 Edge versions",
    "last 7 Safari versions",
    "last 8 Android versions",
    "last 8 ChromeAndroid versions",
    "last 8 FirefoxAndroid versions",
    "last 10 iOS versions",
    "last 5 Opera versions"
  ],
  "engines": {
    "node": ">= 12.22.1",
    "npm": ">= 6.13.4",
    "yarn": ">= 1.21.1"
  }
}
IlCallo commented 2 years ago

Please try again today, there was some havoc yesterday with q/app versions which broke the ability to install/remove AEs into a project

ZaeemKhaliq commented 2 years ago

Removed 'node_modules' and installed extension again so its installed correctly now.

Here are the minimum steps to reproduce the original issue: -

First create project with: -

quasar create sample

Select the following options: -

Pick your CSS preprocessor: -> Sass with SCSS syntax

Check the features needed for your project: -> ESLint (recommended) -> Vuex -> Axios

Pick an ESLint preset: (Use arrow keys) -> Prettier (https://github.com/prettier/prettier)

Continue to install project dependencies after the project has been created? (recommended) -> Yes, use NPM

Once project is created, delete 'EssentialLink.vue' file from 'components' folder.

Go to 'layouts' folder, open 'MainLayout.vue' file and change the code to: -

<template>
  <q-layout view="lHh Lpr lFf">
    <q-page-container>
      <router-view />
    </q-page-container>
  </q-layout>
</template>

<script>
import { defineComponent, ref } from "vue";

export default defineComponent({
  name: "MainLayout",
});
</script>

Now go to 'pages' folder, open 'Index.vue' file and change the code to: -

<template>
  <q-page class="flex flex-center">
    <h4>Welcome to app!</h4>
    <br />
    <q-icon :name="outlinedPlayArrow" class="icon" />
  </q-page>
</template>

<script>
import { defineComponent } from "vue";
import { outlinedPlayArrow } from "@quasar/extras/material-icons-outlined";

export default defineComponent({
  name: "PageIndex",
  data() {
    return {
      outlinedPlayArrow: null,
    };
  },
  created() {
    this.outlinedPlayArrow = outlinedPlayArrow;
  },
});
</script>

<style lang="scss">
.icon {
  font-size: 2rem;
}
</style>

Save the files. Next, install the quasar-testing extension with the following command: -

quasar ext add @quasar/testing-unit-jest@^3.0.0-alpha.6

The default version i.e., 2.2.3 or something throws error and doesn't works with latest quasar version.

Now, create the following test case for the 'Index.vue' page in a file named 'Index.spec.js': -

import { describe, expect, it } from "@jest/globals";
import { mount, shallowMount } from "@vue/test-utils";

import Index from "../../../../src/pages/Index.vue";

describe("Index", () => {
  it("Renders without errors", () => {
    const wrapper = mount(Index);

    expect(wrapper.html()).toBeTruthy();
  });
});

Now run the test with the command: -

npm run test:unit Index.spec.js

It throws this error initially: -

SyntaxError: Unexpected token 'export'

After making following changes in 'jest.config.js' file: -

const esModules = ["quasar", "quasar/lang", "lodash-es", "@quasar/extras"].join("|");
transformIgnorePatterns: [`node_modules/(?!(${esModules}))`],

It throws this error: -

Test suite failed to run

    RangeError: Maximum call stack size exceeded

at Runtime._execModule (node_modules/jest-runtime/build/index.js:1299:24)
      at Object.<anonymous> (src/pages/Index.vue:11:1)
      at Object.<anonymous> (test/jest/__tests__/sample/Index.spec.js:4:1)
IlCallo commented 2 years ago

The default version i.e., 2.2.3 or something throws error and doesn't works with latest quasar version.

You should use quasar ext add @quasar/testing-unit-jest@alpha, as written into the Qv2 compatible docs

Right now you're using alpha.6, but alpha.7 changed some default settings to fix many problems with using the CJS build of Quasar. Also, you cannot load a component using q-page without providing the needed QLayout stuff, as stated in the docs

Check if these things solve the problem for you, if not I'll take a look

ZaeemKhaliq commented 2 years ago

Tried using the above version of extension, still the same 'Maximum Call Stack' error is occurring.

However, I created a Linux (Ubuntu) virtual machine and tried running the same test. The error is not occurring there.

I guess the issue is most likely related to 'node_modules' or maybe Windows. Maybe cache or something.