cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.

Home Page:https://cypress.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Component testing doesn't work with Vue 3.4's defineModel

OliJeffery opened this issue · comments

Current behavior

defineModel is stable as of Vue 3.4 so we recently refactored a lot of our code to take advantage of it. However, this has broken our component testing. Previously, we were able to pass modelValue as a prop when mounting a component in a component test, like so:

cy.mount(BasicEditor, {
      props: {
        modelValue: {
          ...rest_of_the_obect
        },
      },
    });

and the test would mount the component with the stub data we gave it.

Since moving to defineModel (specifically for this case const rule = defineModel<Object>({ required: true });), it first gives us the error defineModel is not defined. We can get around this by importing defineModel from Vue in the component, though we shouldn't have to as like defineEmits and defineProps, defineModel is automatically available inside <script setup>.

Adding that import in gets us around the initial error, but then we get an error that rule is undefined.

The component itself isn't broken and works in both production and Cypress e2e testing. I've tried upgrading to the latest version of Cypress (13.90 at the time of writing) but get the same results.

Desired behavior

There should be a way of mounting a component that makes use of defineModel and allows you to pass stub data to it. You should also not have to import defineModel.

Test code to reproduce

Test:

import BasicEditor from "@/components/dashboard/config/rules/BasicEditor.vue";
import { createTestingPinia } from "@pinia/testing";
import { setActivePinia } from "pinia";
import { useNetworkStore } from "@/stores/network";
describe("BasicEditor.vue", () => {
  beforeEach(() => {
    const pinia = createTestingPinia({
      createSpy: () => {
        cy.spy();
      },
    });
    setActivePinia(pinia);
  });

  it('does not render any fmc-type="loading" elements', () => {
    const network = useNetworkStore();
    network.getConfigData = () => {
      return {};
    };
    cy.mount(BasicEditor, {
      props: {
        modelValue: {
          editorConfig: {
            alertIdFields: [],
            conditionsArray: [],
            customFields: [],
            fromTable: null,
            groupFields: [],
            postGroupConditions: [],
            selectedFields: [],
          },
          enabled: false,
          modified: "2024-04-12T13:47:37.465",
          pythonCode: null,
          ruleName: null,
          sqlQuery: null,
          tab: 0,
          active: false,
        },
      },
    });
    cy.get('[fmc-type="loading"]').should("not.exist");
  });
});

Partial component script:

<script setup lang="ts">

const rule = defineModel<Object>({ required: true });

const props = defineProps({
  initialQueryName: String,
  extended: [String, Boolean],
  editAccess: Boolean,
});

console.log(rule.value)

</script>

Cypress Version

13.9.0

Node version

20.11.1

Operating System

macOs 11.6

Debug Logs

at rule.value.editorConfig.fromTable.tag (http://localhost:8080/__cypress/src/src/components/dashboard/config/rules/BasicEditor.vue?t=1715773860619:290:18)
    at callWithErrorHandling (http://localhost:8080/__cypress/src/node_modules/.vite/deps/chunk-AIL5YJOT.js?v=32d27e9b:1858:33)
    at ReactiveEffect.getter [as fn] (http://localhost:8080/__cypress/src/node_modules/.vite/deps/chunk-AIL5YJOT.js?v=32d27e9b:3547:22)
    at ReactiveEffect.run (http://localhost:8080/__cypress/src/node_modules/.vite/deps/chunk-AIL5YJOT.js?v=32d27e9b:396:19)
    at doWatch (http://localhost:8080/__cypress/src/node_modules/.vite/deps/chunk-AIL5YJOT.js?v=32d27e9b:3646:26)
    at watch (http://localhost:8080/__cypress/src/node_modules/.vite/deps/chunk-AIL5YJOT.js?v=32d27e9b:3471:10)
    at setup (http://localhost:8080/__cypress/src/src/components/dashboard/config/rules/BasicEditor.vue?t=1715773860619:289:5)
    at callWithErrorHandling (http://localhost:8080/__cypress/src/node_modules/.vite/deps/chunk-AIL5YJOT.js?v=32d27e9b:1858:19)
    at setupStatefulComponent (http://localhost:8080/__cypress/src/node_modules/.vite/deps/chunk-AIL5YJOT.js?v=32d27e9b:9258:25)
    at setupComponent (http://localhost:8080/__cypress/src/node_modules/.vite/deps/chunk-AIL5YJOT.js?v=32d27e9b:9219:36)
From previous event:
    at Promise.longStackTracesCaptureStackTrace [as _captureStackTrace] (http://localhost:8080/__cypress/runner/cypress_runner.js:3486:19)
    at Promise._then (http://localhost:8080/__cypress/runner/cypress_runner.js:1239:17)
    at Promise._passThrough (http://localhost:8080/__cypress/runner/cypress_runner.js:4110:17)
    at Promise.lastly.Promise.finally (http://localhost:8080/__cypress/runner/cypress_runner.js:4119:17)
    at Object.onRunnableRun (http://localhost:8080/__cypress/runner/cypress_runner.js:163586:53)
    at $Cypress.action (http://localhost:8080/__cypress/runner/cypress_runner.js:41042:28)
    at Runnable.run (http://localhost:8080/__cypress/runner/cypress_runner.js:146174:13)
    at next (http://localhost:8080/__cypress/runner/cypress_runner.js:155959:10)
    at <unknown> (http://localhost:8080/__cypress/runner/cypress_runner.js:156003:5)
    at timeslice (http://localhost:8080/__cypress/runner/cypress_runner.js:146514:27)

Other

No response