Skip to content

Commit

Permalink
N21-2052 adjust ctl autocomplete (#3313)
Browse files Browse the repository at this point in the history
  • Loading branch information
arnegns committed Jul 11, 2024
1 parent 901fb3d commit 3573c56
Show file tree
Hide file tree
Showing 21 changed files with 932 additions and 221 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ import { createMock, DeepMocked } from "@golevelup/ts-jest";
import { mount } from "@vue/test-utils";
import { nextTick, ref } from "vue";
import ContextExternalToolConfigurator from "./ContextExternalToolConfigurator.vue";
import { createModuleMocks } from "@/utils/mock-store-module";
import NotifierModule from "@/store/notifier";
import { NOTIFIER_MODULE_KEY } from "@/utils/inject";

jest.mock(
"@data-external-tool/contextExternalToolConfigurationState.composable"
Expand All @@ -39,9 +42,14 @@ describe("CourseContextExternalToolConfigurator", () => {
const getWrapper = (
props: ComponentProps<typeof ContextExternalToolConfigurator>
) => {
const notifierModule = createModuleMocks(NotifierModule);

const wrapper = mount(ContextExternalToolConfigurator, {
global: {
plugins: [createTestingVuetify(), createTestingI18n()],
provide: {
[NOTIFIER_MODULE_KEY.valueOf()]: notifierModule,
},
},
props,
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
import * as useExternalToolUtilsComposable from "@/composables/external-tool-mappings.composable";
import { SchoolExternalTool } from "@/store/external-tool";
import { BusinessError } from "@/store/types/commons";
import { ToolParameterLocation } from "@/store/external-tool";
import NotifierModule from "@/store/notifier";
import { ComponentProps } from "@/types/vue";
import { NOTIFIER_MODULE_KEY } from "@/utils/inject";
import { createModuleMocks } from "@/utils/mock-store-module";
import {
schoolExternalToolConfigurationTemplateFactory,
schoolExternalToolFactory,
toolParameterFactory,
} from "@@/tests/test-utils/factory";
import {
createTestingI18n,
createTestingVuetify,
} from "@@/tests/test-utils/setup";
import {
ContextExternalTool,
ExternalToolConfigurationTemplate,
} from "@data-external-tool";
import { mount, VueWrapper } from "@vue/test-utils";
import { VBtn } from "vuetify/lib/components/index.mjs";
import { createMock } from "@golevelup/ts-jest";
import { flushPromises, mount } from "@vue/test-utils";
import { VAutocomplete, VBtn } from "vuetify/lib/components/index.mjs";
import ExternalToolConfigSettings from "./ExternalToolConfigSettings.vue";
import ExternalToolConfigurator from "./ExternalToolConfigurator.vue";

describe("ExternalToolConfigurator", () => {
Expand All @@ -25,15 +27,17 @@ describe("ExternalToolConfigurator", () => {
getBusinessErrorTranslationKey: () => "",
});

const getWrapper = (props: {
templates: ExternalToolConfigurationTemplate[];
configuration?: SchoolExternalTool | ContextExternalTool;
error?: BusinessError;
loading?: boolean;
}) => {
const getWrapper = (
props: ComponentProps<typeof ExternalToolConfigurator>
) => {
const notifierModule = createModuleMocks(NotifierModule);

const wrapper = mount(ExternalToolConfigurator, {
global: {
plugins: [createTestingVuetify(), createTestingI18n()],
provide: {
[NOTIFIER_MODULE_KEY.valueOf()]: notifierModule,
},
},
props,
});
Expand All @@ -47,91 +51,158 @@ describe("ExternalToolConfigurator", () => {
jest.clearAllMocks();
});

describe("autocomplete", () => {
describe("when selecting a new configuration", () => {
describe("Search box", () => {
describe("when editing a configuration", () => {
const setup = () => {
const template = schoolExternalToolConfigurationTemplateFactory.build({
logoUrl: "some logo",
});
const template = schoolExternalToolConfigurationTemplateFactory.build();

const { wrapper } = getWrapper({
templates: [template],
configuration: schoolExternalToolFactory.build(),
});

const openSelect = async (wrapper: VueWrapper) => {
await wrapper
.find('[data-testId="configuration-select"]')
.trigger("click");

await wrapper
.find(".menuable__content__active .v-list-item:firstChild")
.trigger("click");
};

return {
wrapper,
template,
openSelect,
};
};

// TODO: comment in the test when https://github.com/vuetifyjs/vuetify/pull/16272 is merged
it.skip("should display name and logo of an tool configuration in selection list", async () => {
const { wrapper, template, openSelect } = setup();

await openSelect(wrapper);
it("should disable the selection", async () => {
const { wrapper } = setup();

const selectionRow = wrapper.find(".row");
const select = wrapper
.findComponent('[data-testId="configuration-select"]')
.get("input");

expect(selectionRow.find(".v-image__image").exists()).toBeTruthy();
expect(selectionRow.find("span").text()).toEqual(
expect.stringContaining(template.name)
);
expect(select.attributes("disabled")).toBeDefined();
});

// TODO: comment in the test when https://github.com/vuetifyjs/vuetify/pull/16272 is merged
it.skip("should set enable the save button", async () => {
const { wrapper, openSelect } = setup();

await openSelect(wrapper);
it("should display the edited tool in the selection", async () => {
const { wrapper, template } = setup();

const button = wrapper.find('[data-testId="save-button"]');
const selectionRow = wrapper.find(".v-autocomplete .v-list-item-title");

expect(button.attributes("disabled")).toBeUndefined();
expect(selectionRow.text()).toEqual(template.name);
});
});

describe("when editing a configuration", () => {
describe("when clicking on the 'paste' icon", () => {
const setup = () => {
const clipboardText = "https://google.de";
const template = schoolExternalToolConfigurationTemplateFactory.build();

const clipboardMock = createMock<Clipboard>();
Object.assign(navigator, { clipboard: clipboardMock });

const { wrapper } = getWrapper({
templates: [template],
configuration: schoolExternalToolFactory.build(),
});

clipboardMock.readText.mockResolvedValue(clipboardText);

return {
wrapper,
template,
clipboardMock,
clipboardText,
};
};

it("should disable the selection", async () => {
const { wrapper } = setup();
it("should paste the text from the clipboard into the input field", async () => {
const { wrapper, clipboardMock, clipboardText } = setup();

const select = wrapper
.findComponent('[data-testId="configuration-select"]')
.get("input");
const icon = wrapper
.find(".v-input__append")
.find(".v-icon--clickable");
await icon.trigger("click");
await flushPromises();

expect(select.attributes("disabled")).toBeDefined();
const autocomplete = wrapper.findComponent(VAutocomplete);

expect(clipboardMock.readText).toHaveBeenCalled();
expect(autocomplete.props().search).toEqual(clipboardText);
});
});

it("should display the edited tool in the selection", async () => {
describe("when pasting a url for an existing tool into the search box", () => {
beforeEach(() => {
const vueTeleportDiv = document.createElement("div");
vueTeleportDiv.className = "v-overlay-container";
document.body.appendChild(vueTeleportDiv);
});

afterEach(() => {
document.body.innerHTML = "";
});

const setup = () => {
const template = schoolExternalToolConfigurationTemplateFactory.build({
baseUrl: "https://test.com/:pathParam1/spacer/:pathParam2",
parameters: [
toolParameterFactory.build({
name: "pathParam1",
location: ToolParameterLocation.PATH,
}),
toolParameterFactory.build({
name: "queryParam1",
location: ToolParameterLocation.QUERY,
}),
toolParameterFactory.build({
name: "pathParam2",
location: ToolParameterLocation.PATH,
}),
],
});

const { wrapper } = getWrapper({
templates: [
template,
schoolExternalToolConfigurationTemplateFactory.build(),
],
});

return {
wrapper,
template,
};
};

it("should only show the matched tool in the selection list", async () => {
const { wrapper, template } = setup();

const selectionRow = wrapper.find(".v-autocomplete .v-list-item-title");
await wrapper.find(".v-field__input").trigger("click");

expect(selectionRow.text()).toEqual(template.name);
const searchInput = wrapper
.find('[data-testId="configuration-select"]')
.find("input");
await searchInput.setValue(
"https://test.com/pathParamValue1/spacer/pathParamValue2?queryParam1=queryParamValue1"
);

const selectionItems = wrapper.findAllComponents(
'[data-testid="configuration-select-item"]'
);

expect(selectionItems.length).toEqual(1);
expect(selectionItems[0].text()).toEqual(template.name);
});

it("should automatically fill the parameters", async () => {
const { wrapper, template } = setup();

const autocomplete = wrapper.findComponent(VAutocomplete);
await autocomplete.setValue(
"https://test.com/pathParamValue1/spacer/pathParamValue2?queryParam1=queryParamValue1",
"search"
);
await autocomplete.setValue(template);

const settings = wrapper.getComponent(ExternalToolConfigSettings);
expect(settings.props().modelValue).toEqual([
"pathParamValue1",
"queryParamValue1",
"pathParamValue2",
]);
});
});
});
Expand Down
Loading

0 comments on commit 3573c56

Please sign in to comment.