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

test(ui): introduce functional tests - WF-125 #712

Draft
wants to merge 5 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
572 changes: 569 additions & 3 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,12 @@
"@typescript-eslint/eslint-plugin": "7.18.0",
"@vitejs/plugin-vue": "^5.0.4",
"@vue/eslint-config-prettier": "^9.0.0",
"@vue/test-utils": "^2.4.6",
"eslint": "^8.39.0",
"eslint-plugin-prettier": "5.1.3",
"eslint-plugin-storybook": "0.8.0",
"eslint-plugin-vue": "^9.28.0",
"jsdom": "^25.0.1",
"prettier": "3.2.5",
"storybook": "8.0.5",
"vite": "^5.2.7",
Expand Down
48 changes: 48 additions & 0 deletions src/ui/src/builder/settings/BuilderSettingsProperties.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { describe, expect, it } from "vitest";
import BuilderSettingsProperties from "./BuilderSettingsProperties.vue";
import { shallowMount } from "@vue/test-utils";
import {
buildMockComponent,
buildMockCore,
mockInstancePath,
mockProvides,
} from "@/tests/mocks";
import injectionKeys from "@/injectionKeys";
import { generateBuilderManager } from "../builderManager";
import { flattenInstancePath } from "@/renderer/instancePath";
import WdsFieldWrapper from "@/wds/WdsFieldWrapper.vue";
import templateMap from "@/core/templateMap";

describe("BuilderSettingsProperties", () => {
it.each(Object.keys(templateMap))(
"should render settings for %s",
(type) => {
const { core } = buildMockCore();
const component = buildMockComponent({ type });
core.addComponent(component);

const ssbm = generateBuilderManager();
ssbm.setSelection(
component.id,
flattenInstancePath(mockInstancePath),
"click",
);

const wrapper = shallowMount(BuilderSettingsProperties, {
global: {
provide: {
...mockProvides,
[injectionKeys.builderManager as symbol]: ssbm,
[injectionKeys.core as symbol]: core,
},
},
});

// check that each fields is renderer
expect(wrapper.findAllComponents(WdsFieldWrapper)).toHaveLength(
// @ts-expect-error TS doesn't infer the right type for the component
Object.keys(templateMap[type].writer.fields).length,
);
},
);
});
58 changes: 58 additions & 0 deletions src/ui/src/components/core/input/CoreCheckboxInput.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { describe, expect, it, vi } from "vitest";

import CoreCheckboxInput from "./CoreCheckboxInput.vue";
import { flushPromises, mount } from "@vue/test-utils";
import injectionKeys from "@/injectionKeys";
import { ref } from "vue";
import { buildMockComponent, buildMockCore, mockProvides } from "@/tests/mocks";

describe("CoreCheckboxInput", () => {
it("should render value from the state and forward emit", async () => {
const { core, userState } = buildMockCore();
userState.value = { key: ["b"] };

core.addComponent(
buildMockComponent({
handlers: { "wf-options-change": "python_handler" },
binding: {
eventType: "",
stateRef: "key",
},
}),
);

const wrapper = mount(CoreCheckboxInput, {
global: {
provide: {
...mockProvides,
[injectionKeys.core as symbol]: core,
[injectionKeys.evaluatedFields as symbol]: {
label: ref("This is the label"),
orientation: ref("horizontal"),
options: ref({ a: "Option A", b: "Option B" }),
},
},
},
});

await flushPromises();

const options = wrapper.findAll("input");
expect(options).toHaveLength(2);

const optionA = options.at(0);
expect(optionA.attributes().value).toBe("a");
expect(optionA.element.checked).toBe(false);

const optionB = options.at(1);
expect(optionB.attributes().value).toBe("b");
expect(optionB.element.checked).toBe(true);

const dispatchEvent = vi.spyOn(wrapper.vm.$el, "dispatchEvent");
await optionA.trigger("input");
await flushPromises();
expect(dispatchEvent).toHaveBeenCalledOnce();

expect(wrapper.element).toMatchSnapshot();
});
});
50 changes: 50 additions & 0 deletions src/ui/src/components/core/input/CoreDateInput.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { describe, expect, it, vi } from "vitest";

import CoreDateInput from "./CoreDateInput.vue";
import { flushPromises, mount } from "@vue/test-utils";
import injectionKeys from "@/injectionKeys";
import { ref } from "vue";
import { buildMockComponent, buildMockCore, mockProvides } from "@/tests/mocks";

describe("CoreDateInput", () => {
it("should render value from the state and forward emit", async () => {
const { core, userState } = buildMockCore();
userState.value = { key: "2024-12-14" };
core.addComponent(
buildMockComponent({
handlers: { "wf-date-change": "python_handler" },
binding: {
eventType: "",
stateRef: "key",
},
}),
);

const wrapper = mount(CoreDateInput, {
global: {
provide: {
...mockProvides,
[injectionKeys.core as symbol]: core,
[injectionKeys.evaluatedFields as symbol]: {
label: ref("This is the label"),
},
},
},
});

await flushPromises();

const input = wrapper.get("input");
expect(input.element.value).toStrictEqual("2024-12-14");

const dispatchEvent = vi.spyOn(wrapper.vm.$el, "dispatchEvent");

await input.trigger("change");

await flushPromises();

expect(dispatchEvent).toHaveBeenCalledOnce();

expect(wrapper.element).toMatchSnapshot();
});
});
58 changes: 58 additions & 0 deletions src/ui/src/components/core/input/CoreRadioInput.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { describe, expect, it, vi } from "vitest";

import CoreRadioInput from "./CoreRadioInput.vue";
import { flushPromises, mount } from "@vue/test-utils";
import injectionKeys from "@/injectionKeys";
import { ref } from "vue";
import { buildMockComponent, buildMockCore, mockProvides } from "@/tests/mocks";

describe("CoreRadioInput", () => {
it("should render value from the state and forward emit", async () => {
const { core, userState } = buildMockCore();
userState.value = { key: "b" };

core.addComponent(
buildMockComponent({
handlers: { "wf-option-change": "python_handler" },
binding: {
eventType: "",
stateRef: "key",
},
}),
);

const wrapper = mount(CoreRadioInput, {
global: {
provide: {
...mockProvides,
[injectionKeys.core as symbol]: core,
[injectionKeys.evaluatedFields as symbol]: {
label: ref("This is the label"),
orientation: ref("horizontal"),
options: ref({ a: "Option A", b: "Option B" }),
},
},
},
});

await flushPromises();

const options = wrapper.findAll("input");
expect(options).toHaveLength(2);

const optionA = options.at(0);
expect(optionA.attributes().value).toBe("a");
expect(optionA.element.checked).toBe(false);

const optionB = options.at(1);
expect(optionB.attributes().value).toBe("b");
expect(optionB.element.checked).toBe(true);

const dispatchEvent = vi.spyOn(wrapper.vm.$el, "dispatchEvent");
await optionA.trigger("input");
await flushPromises();
expect(dispatchEvent).toHaveBeenCalledOnce();

expect(wrapper.element).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`CoreCheckboxInput > should render value from the state and forward emit 1`] = `
<div
class="BaseInputWrapper CoreCheckboxInput"
data-v-7a72f1be=""
data-v-7e12caaf=""
>
<label
data-v-7e12caaf=""
>
This is the label
</label>
<div
class="options horizontal"
data-v-7a72f1be=""
>
<div
class="option"
data-v-7a72f1be=""
>
<input
data-v-7a72f1be=""
type="checkbox"
value="a"
/>
<label
data-v-7a72f1be=""
for="component-id-test:0-option-a"
>
Option A
</label>
</div>
<div
class="option"
data-v-7a72f1be=""
>
<input
data-v-7a72f1be=""
type="checkbox"
value="b"
/>
<label
data-v-7a72f1be=""
for="component-id-test:0-option-b"
>
Option B
</label>
</div>
</div>
</div>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`CoreDateInput > should render value from the state and forward emit 1`] = `
<div
class="BaseInputWrapper CoreDateInput"
data-v-7e12caaf=""
data-v-acf95c76=""
>
<label
data-v-7e12caaf=""
>
This is the label
</label>
<input
data-v-acf95c76=""
type="date"
/>
</div>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`CoreRadioInput > should render value from the state and forward emit 1`] = `
<div
class="BaseInputWrapper CoreRadioInput"
data-v-7e12caaf=""
data-v-d075b11d=""
>
<label
data-v-7e12caaf=""
>
This is the label
</label>
<div
class="options horizontal"
data-v-d075b11d=""
>
<div
class="option"
data-v-d075b11d=""
>
<input
data-v-d075b11d=""
id="component-id-test:0-option-a"
name="component-id-test:0-options"
type="radio"
value="a"
/>
<label
data-v-d075b11d=""
for="component-id-test:0-option-a"
>
Option A
</label>
</div>
<div
class="option"
data-v-d075b11d=""
>
<input
data-v-d075b11d=""
id="component-id-test:0-option-b"
name="component-id-test:0-options"
type="radio"
value="b"
/>
<label
data-v-d075b11d=""
for="component-id-test:0-option-b"
>
Option B
</label>
</div>
</div>
</div>
`;
Loading
Loading