Merge pull request #14288 from mvdbeek/fix_tag_autocomplete

[22.05] Fix tag autocomplete for strings that need url encoding
This commit is contained in:
David López
2022-07-11 10:50:19 +02:00
committed by GitHub
2 changed files with 28 additions and 57 deletions
+11 -10
View File
@@ -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
View File
@@ -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;
});
*/
});
});