Unverified Commit fd2dbf51 authored by David López's avatar David López Committed by GitHub
Browse files

Merge pull request #14288 from mvdbeek/fix_tag_autocomplete

[22.05] Fix tag autocomplete for strings that need url encoding
parents fff4e682 e52130b0
Loading
Loading
Loading
Loading
+11 −10
Original line number Diff line number Diff line
@@ -57,10 +57,11 @@ export class TagService {
        if (!tag.valid) {
            throw new Error("Invalid tag");
        }
        const url = `${getAppRoot()}tag/add_tag_async?item_id=${id}&item_class=${itemClass}&context=${context}&new_tag=${
            tag.text
        }`;
        const response = await axios.get(url);
        const url = `${getAppRoot()}tag/add_tag_async`;
        const config = {
            params: { item_id: id, item_class: itemClass, context: context, new_tag: tag.text },
        };
        const response = await axios.get(url, config);
        if (response.status !== 200) {
            throw new Error(`Unable to save tag: ${tag}`);
        }
@@ -75,10 +76,9 @@ export class TagService {
    async delete(rawTag) {
        const { id, itemClass, context } = this;
        const tag = createTag(rawTag);
        const url = `${getAppRoot()}tag/remove_tag_async?item_id=${id}&item_class=${itemClass}&context=${context}&tag_name=${
            tag.text
        }`;
        const response = await axios.get(url);
        const url = `${getAppRoot()}tag/remove_tag_async`;
        const config = { params: { item_id: id, item_class: itemClass, context: context, tag_name: tag.text } };
        const response = await axios.get(url, config);
        if (response.status !== 200) {
            throw new Error(`Unable to delete tag: ${tag}`);
        }
@@ -92,8 +92,9 @@ export class TagService {
     */
    async autocomplete(searchText) {
        const { id, itemClass } = this;
        const url = `${getAppRoot()}tag/tag_autocomplete_data?item_id=${id}&item_class=${itemClass}&q=${searchText}`;
        const response = await axios.get(url);
        const url = `${getAppRoot()}tag/tag_autocomplete_data`;
        const config = { params: { item_id: id, item_class: itemClass, q: searchText } };
        const response = await axios.get(url, config);
        if (response.status !== 200) {
            throw new Error(`Unable to retrieve autocomplete tags for search string: ${searchText}`);
        }
+17 −47
Original line number Diff line number Diff line
@@ -2,9 +2,6 @@ import axios from "axios";
import MockAdapter from "axios-mock-adapter";
import { TagService } from "./tagService";
import { createTag } from "./model";
//import { interval } from "rxjs";
//import { take, takeUntil } from "rxjs/operators";
// test response
import autocompleteResponse from "./testData/autocompleteResponse.txt";

describe("Tags/tagService.js", () => {
@@ -15,6 +12,12 @@ describe("Tags/tagService.js", () => {
        context: "",
        debounceInterval: 50, // shorter value than default for unit tests
    };
    const testLabel = "fo0bar123";
    const expectedParams = {
        item_id: 123,
        item_class: "fooClass",
        context: "",
    };

    const svc = new TagService(svcParams);
    beforeEach(() => {
@@ -26,43 +29,43 @@ describe("Tags/tagService.js", () => {
    });

    describe("save", () => {
        const testLabel = "fo0bar123";
        const testTag = createTag(testLabel);

        const { id, itemClass, context } = svcParams;
        const expectedSaveUrl = `/tag/add_tag_async?item_id=${id}&item_class=${itemClass}&context=${context}&new_tag=${testLabel}`;
        const expectedSaveUrl = `/tag/add_tag_async`;

        it("should save a string tag", async () => {
            const savedTag = await svc.save(testLabel);
            expect(savedTag.text).toBe(testLabel);
            expect(axiosMock.history.get[0].url).toBe(expectedSaveUrl);
            expect(axiosMock.history.get[0].params).toEqual({ ...expectedParams, new_tag: testLabel });
        });

        it("should save an object tag", async () => {
            const savedTag = await svc.save(testTag);
            expect(savedTag.text).toBe(testLabel);
            expect(axiosMock.history.get[0].url).toBe(expectedSaveUrl);
            expect(axiosMock.history.get[0].params).toEqual({ ...expectedParams, new_tag: testLabel });
        });

        // TODO: test error conditions
    });
    describe("delete", () => {
        const testLabel = "fo0bar123";
        const testTag = createTag(testLabel);

        const { id, itemClass, context } = svcParams;
        const expectedDeleteUrl = `/tag/remove_tag_async?item_id=${id}&item_class=${itemClass}&context=${context}&tag_name=${testLabel}`;
        const expectedDeleteUrl = `/tag/remove_tag_async`;

        it("should delete a text tag", async () => {
            const result = await svc.delete(testTag);
            expect(result).toBeTruthy();
            expect(axiosMock.history.get[0].url).toBe(expectedDeleteUrl);
            expect(axiosMock.history.get[0].params).toEqual({ ...expectedParams, tag_name: testLabel });
        });

        it("should delete an object tag", async () => {
            const result = await svc.delete(testTag);
            expect(result).toBeTruthy();
            expect(axiosMock.history.get[0].url).toBe(expectedDeleteUrl);
            expect(axiosMock.history.get[0].params).toEqual({ ...expectedParams, tag_name: testLabel });
        });

        // TODO: test error conditions
@@ -70,8 +73,7 @@ describe("Tags/tagService.js", () => {

    describe("autocomplete", () => {
        const searchString = "foo";
        const { id, itemClass } = svcParams;
        const expectedSearchUrl = `/tag/tag_autocomplete_data?item_id=${id}&item_class=${itemClass}&q=${searchString}`;
        const expectedSearchUrl = `/tag/tag_autocomplete_data`;

        const checkAutocompleteResult = (result) => {
            expect(result).toBeTruthy();
@@ -83,46 +85,14 @@ describe("Tags/tagService.js", () => {

        // straight ajax request, unused in practice, but it's easier to
        // test this call if we just expose it
        const { ...searchParams } = expectedParams;
        delete searchParams.context;

        it("ajax call should return tag objects", async () => {
            const result = await svc.autocomplete(searchString);
            expect(axiosMock.history.get[0].url).toBe(expectedSearchUrl);
            expect(axiosMock.history.get[0].params).toEqual({ ...searchParams, q: searchString });
            checkAutocompleteResult(result);
        });

        /*

        // hit the search input with multiple entries, only one ajax call
        // should result because of debouncing
        it("should debounce autocomplete search inputs", (done) => {
            // stub ajax request to return the success response if the
            // searchString is the expected input

            // take first emission, debouncing should guarantee the first
            // emission is the last thing we sent, should be searchString
            const timer$ = interval(100).pipe(take(1));
            const option$ = svc.autocompleteOptions.pipe(takeUntil(timer$));

            const nextHandler = jest.fn();

            option$.subscribe({
                next: nextHandler,
                error: (err) => console.warn("error", err),
                complete: () => {
                    expect(nextHandler).toHaveBeenCalledTimes(1);
                    expect(axiosMock.history.get.length).toBe(1);
                    done();
                },
            });

            // spam a bunch of key inputs followed by the correct input
            const spamCount = 2 + Math.floor(Math.random() * 10);
            for (let i = 0; i < spamCount; i++) {
                const spamVal = new String(Math.random());
                svc.autocompleteSearchText = spamVal;
            }
            svc.autocompleteSearchText = searchString;
        });

        */
    });
});