import { getLocalVue } from "@tests/vitest/helpers";
import { mount } from "@vue/test-utils";
import flushPromises from "flush-promises";
import { describe, expect, it } from "vitest";
import { useServerMock } from "@/api/client/__mocks__";
import { OK_PLUGIN_STATUS } from "@/components/ConfigTemplates/test_fixtures";
import type { ObjectStoreTemplateSummary } from "@/components/ObjectStore/Templates/types";
import type { UserConcreteObjectStore } from "./types";
import CreateForm from "./CreateForm.vue";
const FAKE_OBJECT_STORE: UserConcreteObjectStore = {
name: "My New Name",
template_id: "moo",
template_version: 0,
active: true,
badges: [],
hidden: false,
private: false,
purged: false,
quota: {
enabled: false,
},
type: "aws_s3",
uuid: "test_UUID",
variables: {
myvar: "default",
},
secrets: ["mysecret"],
};
const STANDARD_TEMPLATE: ObjectStoreTemplateSummary = {
type: "aws_s3",
name: "moo",
description: null,
variables: [
{
name: "myvar",
type: "string",
help: "*myvar help*",
default: "default",
},
],
secrets: [
{
name: "mysecret",
help: "**mysecret help**",
},
],
id: "moo",
version: 0,
badges: [],
hidden: false,
};
const SIMPLE_TEMPLATE: ObjectStoreTemplateSummary = {
type: "aws_s3",
name: "moo",
description: null,
variables: [
{
name: "myvar",
type: "string",
help: "*myvar help*",
default: "default",
},
],
secrets: [
{
name: "mysecret",
help: "**mysecret help**",
},
],
id: "moo",
version: 0,
badges: [],
hidden: false,
};
const OPTIONAL_SECRET_TEMPLATE: ObjectStoreTemplateSummary = {
type: "aws_s3",
name: "moo",
description: null,
variables: [
{
name: "myvar",
type: "string",
help: "myvar help",
default: "default",
},
],
secrets: [
{
name: "optional_secret",
help: "An optional secret",
optional: true,
},
],
id: "moo",
version: 0,
badges: [],
hidden: false,
};
const OPTIONAL_VAR_WITH_VALIDATION_TEMPLATE: ObjectStoreTemplateSummary = {
type: "aws_s3",
name: "moo",
description: null,
variables: [
{
name: "optional_var",
type: "string",
help: "optional var help",
default: "",
optional: true,
validators: [
{
type: "length",
min: 5,
message: "Must be at least 5 characters",
negate: false,
implicit: false,
},
],
},
],
secrets: [
{
name: "mysecret",
help: "mysecret help",
optional: true,
},
],
id: "moo",
version: 0,
badges: [],
hidden: false,
};
const localVue = getLocalVue(true);
const { server, http } = useServerMock();
describe("CreateForm", () => {
it("should render a form with admin markdown converted to HTML in help", async () => {
const wrapper = mount(CreateForm as object, {
propsData: {
template: STANDARD_TEMPLATE,
},
localVue,
});
await flushPromises();
const varFormEl = wrapper.find("#form-element-myvar");
expect(varFormEl).toBeTruthy();
expect(varFormEl.html()).toContain("myvar help");
const secretFormEl = wrapper.find("#form-element-mysecret");
expect(secretFormEl).toBeTruthy();
expect(secretFormEl.html()).toContain("mysecret help");
});
it("should post to create a new object store on submit", async () => {
const wrapper = mount(CreateForm as object, {
propsData: {
template: SIMPLE_TEMPLATE,
},
localVue,
});
server.use(
http.post("/api/object_store_instances", ({ response }) => {
return response(200).json(FAKE_OBJECT_STORE);
}),
http.post("/api/object_store_instances/test", ({ response }) => {
return response(200).json(OK_PLUGIN_STATUS);
}),
);
const nameForElement = wrapper.find("#form-element-_meta_name");
await nameForElement.find("input").setValue("My New Name");
const passwordElement = wrapper.find("#form-element-mysecret");
await passwordElement.find("input").setValue("mysecretvalue");
const submitElement = wrapper.find("#submit");
await submitElement.trigger("click");
await flushPromises();
const emitted = wrapper.emitted("created") || [];
expect(emitted).toHaveLength(1);
expect(emitted[0][0]).toMatchObject(FAKE_OBJECT_STORE);
});
it("should indicate an error on failure", async () => {
const wrapper = mount(CreateForm as object, {
propsData: {
template: SIMPLE_TEMPLATE,
},
localVue,
});
server.use(
http.post("/api/object_store_instances", ({ response }) => {
return response("4XX").json({ err_msg: "Error creating this", err_code: 400 }, { status: 400 });
}),
http.post("/api/object_store_instances/test", ({ response }) => {
return response(200).json(OK_PLUGIN_STATUS);
}),
);
await flushPromises();
const nameForElement = wrapper.find("#form-element-_meta_name");
nameForElement.find("input").setValue("My New Name");
const passwordElement = wrapper.find("#form-element-mysecret");
await passwordElement.find("input").setValue("mysecretvalue");
expect(wrapper.find("[data-description='object-store-creation-error']").exists()).toBe(false);
const submitElement = wrapper.find("#submit");
await submitElement.trigger("click");
await flushPromises();
const emitted = wrapper.emitted("created") || [];
expect(emitted).toHaveLength(0);
const errorEl = wrapper.find("[data-description='object-store-creation-error']");
expect(errorEl.exists()).toBe(true);
expect(errorEl.html()).toContain("Error creating this");
});
it("should disable submit when there are validation errors", async () => {
const wrapper = mount(CreateForm as object, {
propsData: {
template: SIMPLE_TEMPLATE,
},
localVue,
});
const nameForElement = wrapper.find("#form-element-_meta_name");
await nameForElement.find("input").setValue("My New Name");
// Leave secret empty to trigger validation error
const submitElement = wrapper.find("#submit");
expect(submitElement.classes().includes("g-disabled")).toBe(true);
// Try to click when submit is disabled will not emit created event
await submitElement.trigger("click");
await flushPromises();
const emitted = wrapper.emitted("created") || [];
expect(emitted).toHaveLength(0);
});
it("should allow submission when optional secret is empty", async () => {
server.use(
http.post("/api/object_store_instances", ({ response }) => {
return response(200).json(FAKE_OBJECT_STORE);
}),
http.post("/api/object_store_instances/test", ({ response }) => {
return response(200).json(OK_PLUGIN_STATUS);
}),
);
const wrapper = mount(CreateForm as object, {
propsData: {
template: OPTIONAL_SECRET_TEMPLATE,
},
localVue,
});
const nameForElement = wrapper.find("#form-element-_meta_name");
await nameForElement.find("input").setValue("My New Name");
// Don't fill in the optional secret
const submitElement = wrapper.find("#submit");
expect(submitElement.classes().includes("g-disabled")).toBe(false);
await submitElement.trigger("click");
await flushPromises();
const emitted = wrapper.emitted("created") || [];
expect(emitted).toHaveLength(1);
});
it("should validate optional fields when they have values", async () => {
const wrapper = mount(CreateForm as object, {
propsData: {
template: OPTIONAL_VAR_WITH_VALIDATION_TEMPLATE,
},
localVue,
});
const nameForElement = wrapper.find("#form-element-_meta_name");
await nameForElement.find("input").setValue("My New Name");
// Set optional field to a value that's too short
const optionalVarElement = wrapper.find("#form-element-optional_var");
await optionalVarElement.find("input").setValue("abc"); // Too short (< 5 chars)
await flushPromises();
const submitElement = wrapper.find("#submit");
expect(submitElement.classes().includes("g-disabled")).toBe(true);
// Fix the validation error
await optionalVarElement.find("input").setValue("validvalue");
await flushPromises();
expect(submitElement.classes().includes("g-disabled")).toBe(false);
});
});