Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jest tests depend on order of imports for defineComponent #2250

Open
Martin-Idel opened this issue Jan 17, 2024 · 2 comments
Open

Jest tests depend on order of imports for defineComponent #2250

Martin-Idel opened this issue Jan 17, 2024 · 2 comments
Assignees
Milestone

Comments

@Martin-Idel
Copy link

Describe the bug

We are using CustomRenderers on top of vuetify and test them with jest, vue-test-utils and testing-library. We had very weird errors during test execution:

console.warn
    [Vue warn]: Property "controlWrapper" was accessed during render but is not defined on instance. 
...
Cannot read properties of undefined (reading 'control')

It turns out that the error happens because of the import order of defineComponent. In our custom renderer, we had the following:

<script lang="ts">
import { ControlElement } from "@jsonforms/core";
import { rendererProps, RendererProps, useJsonFormsEnumControl } from "@jsonforms/vue";
import { useVuetifyControl, ControlWrapper, DisabledIconFocus } from "@jsonforms/vue-vuetify";
import { defineComponent } from "vue";

if this is switched to

<script lang="ts">
import { ControlElement } from "@jsonforms/core";
import { defineComponent } from "vue";
import { rendererProps, RendererProps, useJsonFormsEnumControl } from "@jsonforms/vue";
import { useVuetifyControl, ControlWrapper, DisabledIconFocus } from "@jsonforms/vue-vuetify";

the tests run properly. Note that the display is completely fine.

Expected behavior

Either the import order shouldn't matter, or at least that should be written extremely prominently in the documentation.

Steps to reproduce the issue

Reproduction:

  1. Go to 'https://github.com/Martin-Idel/jsonformsproblem'
  2. Clone the repository and execute yarn install and then yarn test
  3. See error
  4. Go to the file SelectFieldRenderer and switch the order of import { defineComponent } from "vue"; and import { rendererProps, RendererProps, useJsonFormsEnumControl, } from "@jsonforms/vue";
  5. See no error

You can also run yarn dev to see that everything seems nice in the browser.

Most relevant code (see reproduction repo)

<template>
  <control-wrapper
    v-bind="controlWrapper"
    :styles="styles"
    :isFocused="isFocused"
    :appliedOptions="appliedOptions"
  >
    <v-row class="ml-1 mr-1" style="flex-wrap: nowrap">
      <v-select
        :id="control.path.replaceAll('.', '-')"
        :class="styles.control.input"
        :disabled="false"
        :autofocus="appliedOptions.focus"
        :density="'compact'"
        :variant="'underlined'"
        :label="control.label"
        :required="control.required"
        :model-value="control.data"
        :items="useItems"
        :item-title="(item) => item['label']"
        validate-on-blur
        item-value="value"
        v-bind="vuetifyProps('v-select')"
        @update:model-value="onChange"
        @focus="isFocused = true"
        @blur="isFocused = false"
      />
    </v-row>
  </control-wrapper>
</template>

<script lang="ts">
import { ControlElement } from "@jsonforms/core";
import {
  rendererProps,
  RendererProps,
  useJsonFormsEnumControl,
} from "@jsonforms/vue";
import { defineComponent } from "vue";
import { ControlWrapper, DisabledIconFocus } from "@jsonforms/vue-vuetify";
import { useVuetifyControl } from "@jsonforms/vue-vuetify";

const selectFieldRenderer = defineComponent({
  name: "SelectFieldRenderer",
  components: {
    ControlWrapper,
  },
  directives: {
    DisabledIconFocus,
  },
  props: {
    ...rendererProps<ControlElement>(),
  },
  setup(props: RendererProps<ControlElement>) {
    return {
      ...useVuetifyControl(useJsonFormsEnumControl(props), (value) =>
        value !== null ? value : undefined
      ),
    };
  },
  computed: {
    useItems(): unknown[] {
      return (this.control.schema as { enum: string[] }).enum;
    },
  },
});

export default selectFieldRenderer;
</script>

and here is the test:

import "@testing-library/jest-dom";
import TestSelectFieldRenderer from "../testcomponents/TestSelectFieldRenderer.vue";
import { createVuetify } from "vuetify";
import * as components from "vuetify/components";
import * as directives from "vuetify/directives";
import { render } from "@testing-library/vue";

describe("The SelectFieldRenderer component", () => {
  it("displays selected value", async () => {
    const { getByLabelText, getByText } = await setupComponent("First");

    expect(getByLabelText("This is a title")).toBeInTheDocument();
    expect(getByText("First")).toBeInTheDocument();
  });

  const setupComponent = async (value: "First" | "Second" | undefined) => {
    const vuetify = createVuetify({ components, directives });

    return {
      ...render(TestSelectFieldRenderer, {
        global: {
          plugins: [vuetify],
        },
        props: {
          data: { select: value },
          schema:
            // eslint-disable-next-line max-len
            `{"properties":{"select":{"title":"This is a title","type":"string","enum":["First","Second"]}},"type":"object"}`,
          uiSchema:
            '{"type":"VerticalLayout","elements":[{"type":"SelectField","scope":"#/properties/select"}]}',
        },
      }),
    };
  };
});

and the test component:

<template>
  <json-forms
    :data="props.data"
    :schema="JSON.parse(schema)"
    :uischema="JSON.parse(uiSchema)"
    :renderers="renderers"
    :validationMode="'ValidateAndShow'"
  />
</template>

<script lang="ts" setup>
import { rankWith, uiTypeIs } from "@jsonforms/core";
import { JsonForms } from "@jsonforms/vue";
import { vuetifyRenderers } from "@jsonforms/vue-vuetify";
import selectFieldRenderer from "@/components/SelectFieldRenderer.vue";

const props = defineProps({
  data: { type: Object, required: true },
  schema: { type: String, required: true },
  uiSchema: { type: String, required: true },
});

const renderers = Object.freeze([
  ...vuetifyRenderers,
  {
    tester: rankWith(15, uiTypeIs("SelectField")),
    renderer: selectFieldRenderer,
  },
]);
</script>

<style scoped />

Screenshots

No response

Which Version of JSON Forms are you using?

v3.1.0

Framework

Vue

RendererSet

Other (please specify in the Additional context field)

Additional context

We use jsonforms/vue-vuetify renderers in v3.1.0.preview - however I believe the problem resides with jsonforms/vue as that import messes up the test.

@sdirix
Copy link
Member

sdirix commented Jan 17, 2024

Thanks for the report. This is certainly not intended behavior!

@sdirix sdirix added this to the 3.x milestone Jan 17, 2024
@LukasBoll
Copy link
Collaborator

I couldn´t find an obvious reason for this issue. But we think it might be related to circular dependencies in JSON Forms. We created an issue to resolve them in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants