quasarframework / quasar-testing

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

Create a guide to setup testing outside Quasar CLI #263

Open IlCallo opened 2 years ago

IlCallo commented 2 years ago

We often get issues from people who're not using Quasar CLI, thus this repo shouldn't be what they need, but I guess there isn't a guide for that use case at all right now It's definitely possible to deduce how to make it work by checking out existing AE docs and code, but a full fledged guide could be useful too

Anyone which succesfully setup tests in a project using Quasar without Quasar CLI feel free to jump in and take the task, we'll put the guide in an MD file on its own and link it from the main README :)

dirodriguezm commented 1 year ago

Hi, could you give some insights on how to achieve this ? At least some short guidance, not the full tutorial.

Thanks.

HarisSpahija commented 1 year ago

We are currently facing this with our project that the installQuasarPlugin() is very important to make sure that all the components are picked up by test runners like jest. Do you have any pointers to how we can achieve an implementation for this library without Quasar CLI like @dirodriguezm mentioned?

https://github.com/quasarframework/quasar-testing/blob/4bbc0564164df51b4ee864363b06ac8f82d6547c/packages/unit-jest/src/helpers/install-quasar-plugin.ts#L6

IlCallo commented 1 year ago

You should be able to just copy over the helper and use it, there's nothing fancy into it which prevents it to be used outside Quasar CLI project AFAIK

HarisSpahija commented 1 year ago

I did make a repo with some default configuration and it seems like components are not resolving. Is there some additional config we need to add for users in vue-cli?

https://github.com/HarisSpahija/quasar-testing-example-vue-cli

dirodriguezm commented 1 year ago

I ended up installing @quasar/quasar-app-extension-testing-unit-vitest and using installQuasar like the repo documentation says.

Also, note that if you are using Pinia, you need a helper function. Here's what I'm using:

export function installPinia() {
  const globalConfigBackup = config.global;

  beforeAll(() => {
    config.global.plugins.unshift(
      createPinia() as unknown as Plugin
    );
  });

  afterAll(() => {
    config.global = globalConfigBackup;
  });
}

With all the above considerations it finally worked, even with components that require q-layout

HarisSpahija commented 1 year ago

Amazing that you got the vitest side working @dirodriguezm , but sadly I still havent been able to make @quasar/quasar-app-extension-testing-unit-jest work for a project outside of vue-cli. See https://github.com/HarisSpahija/quasar-testing-example-vue-cli

Did you install @quasar/quasar-app-extension-testing-unit-vitest trough npm? Whenever I do the same for jest there is no exported member installQuasarPlugin on @quasar/quasar-app-extension-testing-unit-jest

IlCallo commented 1 year ago

@HarisSpahija are you using the correct version? Jest AE for Qv2 is still in alpha, you need to use alpha tag while installing it, check out the docs

HarisSpahija commented 1 year ago

@IlCallo @quasar/testing-unit-jest@alpha is not an npm package. This ticket is for people that want to use quasar without the quasar-cli. How can I install @quasar/testing-unit-jest@alpha when not in a quasar cli project?

Nvm I figured it out

npm i --save-dev @quasar/quasar-app-extension-testing-unit-jest@alpha
HarisSpahija commented 1 year ago

The component still seems to not be running on a button component. jest.config.js

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

module.exports = {
  preset: "@vue/cli-plugin-unit-jest/presets/typescript-and-babel",
  testMatch: ["<rootDir>/**/*.spec.(js|jsx|ts|tsx)"],
  transform: {
    // See https://jestjs.io/docs/en/configuration.html#transformignorepatterns-array-string
    [`^(${esModules}).+\\.js$`]: "babel-jest",
  },
  transformIgnorePatterns: [`node_modules/(?!(${esModules}))`],
};

Button.spec.ts

import { DOMWrapper, mount } from "@vue/test-utils";
import Button from "./Button.vue";
import { installQuasarPlugin } from "@quasar/quasar-app-extension-testing-unit-jest";

installQuasarPlugin();

describe.only("Button", () => {
  beforeEach(() => {
    mount(Button);
  });

  it("Should render button element", () => {
    const wrapper = new DOMWrapper(document.body);

    expect(wrapper.find("button").exists()).toBeTruthy();
  });
});

Button.vue

<template>
  <q-button color="primary" label="OK" @click="onOKClick" />
</template>

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

export default defineComponent({
  name: "Button",
  emits: ["click"],
  setup(props, { emit }) {
    const onOKClick = () => {
      emit("click");
    };

    return {
      onOKClick,
    };
  },
});
</script>

Error returned:

Screenshot 2022-07-22 at 11 55 48

Repo: https://github.com/HarisSpahija/quasar-testing-example-vue-cli

HarisSpahija commented 1 year ago

I made a comparison component to see if the Button.vue without quasar would render. The goal is to see if a button element is rendered. The problem with quasar is that the test fails.

// Button.vue
<template>
  <button @click="onOKClick">Button</button>
</template>

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

export default defineComponent({
  name: "Button",
  emits: ["click"],
  setup(props, { emit }) {
    const onOKClick = () => {
      emit("click");
    };

    return {
      onOKClick,
    };
  },
});
</script>

// Button.spec.ts
import { mount } from "@vue/test-utils";
import Button from "./Button.vue";

describe("Button", () => {
  it("Should render button element", () => {
    const wrapper = mount(Button);

    console.log(wrapper.html()); // returns <button>Button</button>

    expect(wrapper.find("button").exists()).toBeTruthy();
  });
});

while a button with the installQuasarPlugin fails

// QuasarButton.vue
<template>
  <q-button @click="onOKClick">Button</q-button>
</template>

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

export default defineComponent({
  name: "Button",
  emits: ["click"],
  setup(props, { emit }) {
    const onOKClick = () => {
      emit("click");
    };

    return {
      onOKClick,
    };
  },
});
</script>

// QuasarButton.spec.ts
import { mount } from "@vue/test-utils";
import QuasarButton from "./QuasarButton.vue";
import { installQuasarPlugin } from "@quasar/quasar-app-extension-testing-unit-jest";

installQuasarPlugin();

describe("Button", () => {
  it("Should render button element", () => {
    const wrapper = mount(QuasarButton); // <- fails 

    console.log(wrapper.html());

    expect(wrapper.find("button").exists()).toBeTruthy();
  });
});

The error I get

TypeError: Cannot convert undefined or null to object
        at Function.assign (<anonymous>)

       7 | describe("Button", () => {
       8 |   it("Should render button element", () => {
    >  9 |     const wrapper = mount(QuasarButton);
         |                     ^
      10 |
      11 |     console.log(wrapper.html());
      12 |

      at installQuasar (node_modules/quasar/dist/quasar.cjs.prod.js:6:15228)
      at Object.install (node_modules/quasar/dist/quasar.cjs.prod.js:6:479751)
      at Object.use (node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:4305:28)
      at mount (node_modules/@vue/test-utils/dist/vue-test-utils.cjs.js:8228:25)
      at Object.<anonymous> (src/components/ComponentExample/QuasarButton/QuasarButton.spec.ts:9:21)

I dont know how to get the quasar component to pass even a simple render sanity check. Is there additional config required because the documentation explanation of just inserting the plugin function doesnt seem to work. Here is the repo with project setup: https://github.com/HarisSpahija/quasar-testing-example-vue-cli

I also tried to go trough the vitest approach with vue-cli. But this one returns the same errors where quasar components are not rendered. Is there a chance you can share an example of your implementation @dirodriguezm ?

denisibanez commented 1 year ago

i have problems to, i try install the quasar-app-extension-testing-unit-jest in my vite project (i dont use quasar cli), but i receive the error: TypeError: (0 , _quasarAppExtensionTestingUnitJest.installQuasarPlugin) is not a function...

`import HelloWorld from "./HelloWorld.vue"; import { mount } from "@vue/test-utils"; import { QBtn } from 'quasar'; import { installQuasarPlugin } from "@quasar/quasar-app-extension-testing-unit-jest";

installQuasarPlugin({ plugins: { QBtn } });

test("HelloWorld Component renders", () => { const wrapper = mount(HelloWorld) expect(wrapper).toBeTruthy(); });`

IlCallo commented 1 year ago

@HarisSpahija @denisibanez I'm not sure you'll be able to use helpers exported by a Quasar App Extension into a codebase which isn't using Quasar CLI

That's why in a previous message I suggested this:

You should be able to just copy over the helper and use it

"Copy over the helper" means "copy the code in your project and use it locally" It's very different than installing the published package, which relies on being executed where a @quasar/app-* package is available, and using the helper from there

Once you are able to have a working setup, if you provide me a repo, I'll be able to polish it and publish it as a package for everyone to use when dealing with projects using Quasar but without Quasar CLI


@denisibanez Jest cannot be used for Vite projects, there's a big banner right at the beginning of the Jest AE README. Use Vitest

@HarisSpahija you need to load all Components and Plugins you'll use for the test with the installQuasarPlugin. When using Quasar packages that's usually taken care automatically by the framework, but you're working outside the framework and you should configure everything manually

HarisSpahija commented 1 year ago

@IlCallo Yeah we figured that out and moving to quasar cli solved most of our issues

denisibanez commented 1 year ago

@HarisSpahija @denisibanezNão tenho certeza se você conseguirá usar auxiliares exportados por uma extensão de aplicativo Quasar em uma base de código que não esteja usando o Quasar CLI

É por isso que em uma mensagem anterior sugeri isso:

Você deve ser capaz de copiar o auxiliar e usá-lo

"Copy over the helper" significa "copiar o código em seu projeto e usá-lo localmente" É muito diferente de instalar o pacote publicado, que depende de ser executado onde um @quasar/app-*pacote está disponível, e usar o helper de lá

Assim que você conseguir ter uma configuração de trabalho, se você me fornecer um repositório, poderei aperfeiçoá-lo e publicá-lo como um pacote para todos usarem ao lidar com projetos usando o Quasar, mas sem o Quasar CLI

@denisibanezJest não pode ser usado para projetos Vite, há um grande banner logo no início do Jest AE README. Usar o Vitest

@HarisSpahijavocê precisa carregar todos os componentes e plug-ins que usará para o teste com o arquivo installQuasarPlugin. Ao usar pacotes Quasar que geralmente são atendidos automaticamente pelo framework, mas você está trabalhando fora do framework e deve configurar tudo manualmente

I found this out in the worst possible way lol

I'm using vitest and it worked!

LaisPacific0 commented 1 year ago

Has anyone already configured a project with Quasar without CLI and integrated with Vitest and Vue? I need to create a project with Quasar without CLI, and also with Vue and Vitest. Nowhere did I find how to install all these dependencies and configure them to run a simple test. If anyone has already solved this problem and can help me, I would be grateful

I already tried to install Quasar manually, but when installing Vitest it generates several errors because it is not the Quasar version with the CLI. @IlCallo @denisibanez @dirodriguezm @HarisSpahija

acarter1308 commented 1 year ago

@HarisSpahija in case this is still of any help. I haven't had much time to continue messing with this recently as work has picked up quite a bit, but I wanted to share where I'm at so far using currently available options in case it's useful to or can be continued by anyone else.

Project: Vue-CLI Vue 3 + webpack + Vue CLI Quasar Plugin

{ // package.json
  "dependencies": {
    "@fortawesome/fontawesome-pro": "^6.2.0",
    "@js-joda/core": "^5.5.3",
    "@js-joda/locale_en": "^4.8.10",
    "@js-joda/timezone": "^2.18.0",
    "@quasar/babel-preset-app": "^2.0.2", // *
    "@quasar/extras": "^1.0.0",
    "axios": "^1.4.0",
    "eslint-config-prettier": "^8.8.0",
    "eslint-plugin-prettier": "^4.2.1",
    "jest-transform-stub": "^2.0.0",
    "keycloak-js": "^19.0.3",
    "pinia": "^2.0.22",
    "prettier": "^2.8.8",
    "quasar": "^2.0.0",
    "vue": "^3.0.0",
    "vue-router": "^4.0.3"
  },
  "devDependencies": {
    "@babel/core": "^7.12.16",
    "@babel/eslint-parser": "^7.12.16",
    "@quasar/quasar-app-extension-testing-unit-jest": "^3.0.0-beta.5", // base 3.0.0 did not included jest-prest.mjs
    "@vue/cli-plugin-babel": "~5.0.8", 
    "@vue/cli-plugin-eslint": "~5.0.8",
    "@vue/cli-plugin-router": "~5.0.0",
    "@vue/cli-service": "~5.0.8",
    "@vue/compiler-sfc": "^3.0.0",
    "@vue/test-utils": "^2.4.0",
    "@vue/vue3-jest": "^27.0.0",
    "babel-jest": "^27.0.6",
    "eslint": "^7.32.0",
    "eslint-plugin-vue": "^8.0.3",
    "jest": "^27.0.6",
    "sass": "1.32.12",
    "sass-loader": "^12.0.0",
    "vue-cli-plugin-quasar": "~5.0.1"
  }
}

With the jest and babel configs, I ripped the settings straight out of a fresh Quasar CLI + @quasar/testing project (with slight modifications).

// jest.config.js
module.exports = {
// point to jest-preset.mjs (base config) file in the library
  preset: '@quasar/quasar-app-extension-testing-unit-jest',
// override these to conform to project structure / test directory
  testMatch: [
    '<rootDir>/tests/unit/**/*.(spec|test).+(ts|js)?(x)',
    '<rootDir>/src/**/*.jest.(spec|test).+(ts|js)?(x)',
  ],
  collectCoverage: true,
// the transforms are copied from the jest-preset.mjs file mentioned above, but includes the 'babel-jest' entry
  transform: {
    '.*\\.js$': 'babel-jest',
    '.*\\.vue$': ['@vue/vue3-jest', { pug: { doctype: 'html' } }],
    '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
      'jest-transform-stub',
  },
};
// babel.config.js
module.exports = (api) => {
  const envOptions = {};

  if (api.caller((caller) => caller && caller.target === "node")) {
    envOptions.targets = { node: "current" };
  }

  if (api.env() === "test") {
    envOptions.modules = "commonjs";
    envOptions.targets = { node: "current" };
  }

  return {
    presets: [["@quasar/babel-preset-app", envOptions]],
  };
};

I was able to get the following test to pass without complaining that 'installQuasarPlugin()' was not a function, which is where I got stuck initially.

// componentTest.spec.js
import { mount } from '@vue/test-utils';
import { installQuasarPlugin } from '@quasar/quasar-app-extension-testing-unit-jest';
import { scheduleTableColumns } from '../../src/utils/tableUtil';
import ScheduleTable from '../../src/components/ScheduleTable.vue';

installQuasarPlugin();

describe('tests relating to page component visibility', () => {
  let wrapper;
  it('should display the schedule table', () => {
    wrapper = mount(ScheduleTable, {
      props: {
        columns: scheduleTableColumns,
      },
    });
    expect(wrapper.isVisible()).toBe(true);
  });
});

I'll try to report back once I get time to write some real tests on my components and see what I run into.