Skip to content

Commit

Permalink
N21-2409 Open link of link element in the same window when referencin…
Browse files Browse the repository at this point in the history
…g the current page (#3565)
  • Loading branch information
MarvinOehlerkingCap authored Feb 26, 2025
1 parent f11895c commit 0c18e34
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ describe("LinkContentElement", () => {
return { wrapper };
};

const setup = (
const setupWrapper = (
options: {
content?: LinkElementContent;
isEditMode: boolean;
Expand Down Expand Up @@ -169,7 +169,7 @@ describe("LinkContentElement", () => {
describe("when link element is displayed", () => {
describe("when content url is undefined", () => {
it("should not render display of link content", () => {
const { wrapper } = setup({
const { wrapper } = setupWrapper({
isEditMode: true,
});

Expand All @@ -181,7 +181,7 @@ describe("LinkContentElement", () => {
});

it("should not render link element menu", () => {
const { wrapper } = setup({
const { wrapper } = setupWrapper({
isEditMode: false,
});

Expand All @@ -191,7 +191,7 @@ describe("LinkContentElement", () => {
});

it("should not have an aria-label", () => {
const { wrapper } = setup({
const { wrapper } = setupWrapper({
isEditMode: true,
});

Expand All @@ -204,7 +204,7 @@ describe("LinkContentElement", () => {
describe("when content url is defined", () => {
it("should render display of link content with correct props", () => {
const linkElementContent = linkElementContentFactory.build();
const { wrapper, element } = setup({
const { wrapper, element } = setupWrapper({
content: linkElementContent,
isEditMode: true,
});
Expand All @@ -220,7 +220,7 @@ describe("LinkContentElement", () => {

it("should have the correct aria-label", () => {
const linkElementContent = linkElementContentFactory.build();
const { wrapper, element } = setup({
const { wrapper, element } = setupWrapper({
content: linkElementContent,
isEditMode: true,
});
Expand All @@ -239,7 +239,7 @@ describe("LinkContentElement", () => {
"should 'emit move-keyboard:edit' when arrow key %s is pressed",
async (key) => {
const linkElementContent = linkElementContentFactory.build();
const { wrapper } = setup({
const { wrapper } = setupWrapper({
content: linkElementContent,
isEditMode: true,
});
Expand All @@ -260,7 +260,7 @@ describe("LinkContentElement", () => {
"should not 'emit move-keyboard:edit' when arrow key %s is pressed and element is in view mode",
async (key) => {
const linkElementContent = linkElementContentFactory.build();
const { wrapper } = setup({
const { wrapper } = setupWrapper({
content: linkElementContent,
isEditMode: false,
});
Expand All @@ -279,7 +279,7 @@ describe("LinkContentElement", () => {
describe("link element menu", () => {
it("should render link element menu", () => {
const linkElementContent = linkElementContentFactory.build();
const { wrapper } = setup({
const { wrapper } = setupWrapper({
content: linkElementContent,
isEditMode: true,
});
Expand All @@ -291,7 +291,7 @@ describe("LinkContentElement", () => {

it("should emit 'move-down:edit' event when move down menu item is clicked", async () => {
const linkElementContent = linkElementContentFactory.build();
const { wrapper } = setup({
const { wrapper } = setupWrapper({
content: linkElementContent,
isEditMode: true,
});
Expand All @@ -304,7 +304,7 @@ describe("LinkContentElement", () => {

it("should emit 'move-up:edit' event when move up menu item is clicked", async () => {
const linkElementContent = linkElementContentFactory.build();
const { wrapper } = setup({
const { wrapper } = setupWrapper({
content: linkElementContent,
isEditMode: true,
});
Expand All @@ -317,7 +317,7 @@ describe("LinkContentElement", () => {

it("should emit 'delete:element' event when delete menu item is clicked", async () => {
const linkElementContent = linkElementContentFactory.build();
const { wrapper } = setup({
const { wrapper } = setupWrapper({
content: linkElementContent,
isEditMode: true,
});
Expand All @@ -328,13 +328,83 @@ describe("LinkContentElement", () => {
expect(wrapper.emitted()).toHaveProperty("delete:element");
});
});

describe("when the link references a different page", () => {
const setup = () => {
const url = new URL("https://dbildungscloud.test/path");
const linkElementContent = linkElementContentFactory.build({
url: url.toString(),
});
Object.defineProperty(window, "location", {
get: () =>
createMock<Location>({
host: url.host,
pathname: "/otherPath",
}),
});

const { wrapper } = setupWrapper({
content: linkElementContent,
isEditMode: false,
});

return {
wrapper,
};
};

it("should open in a new tab", () => {
const { wrapper } = setup();

const linkElement = wrapper.findComponent(
'[data-testid="board-link-element"]'
);

expect(linkElement.attributes("target")).toEqual("_blank");
});
});

describe("when the link references the same page", () => {
const setup = () => {
const url = new URL("https://dbildungscloud.test/path");
const linkElementContent = linkElementContentFactory.build({
url: url.toString(),
});
Object.defineProperty(window, "location", {
get: () =>
createMock<Location>({
host: url.host,
pathname: url.pathname,
}),
});

const { wrapper } = setupWrapper({
content: linkElementContent,
isEditMode: false,
});

return {
wrapper,
};
};

it("should open in the same tab", () => {
const { wrapper } = setup();

const linkElement = wrapper.findComponent(
'[data-testid="board-link-element"]'
);

expect(linkElement.attributes("target")).toEqual("_self");
});
});
});
});

describe("when link element is being created", () => {
describe("when element is in view mode", () => {
it("should hide link element in view mode when no url was entered", () => {
const { wrapper } = setup({
const { wrapper } = setupWrapper({
isEditMode: false,
});

Expand All @@ -346,7 +416,7 @@ describe("LinkContentElement", () => {
});

it("should not render link element menu in view mode", () => {
const { wrapper } = setup({
const { wrapper } = setupWrapper({
isEditMode: false,
});

Expand All @@ -358,7 +428,7 @@ describe("LinkContentElement", () => {

describe("when element is in edit mode", () => {
it("should render LinkContentElementCreate component when in editmode", () => {
const { wrapper } = setup({ isEditMode: true });
const { wrapper } = setupWrapper({ isEditMode: true });

const linkCreateComponent = wrapper.findComponent(
LinkContentElementCreate
Expand All @@ -370,7 +440,7 @@ describe("LinkContentElement", () => {
it.each(["up", "down"])(
"should not 'emit move-keyboard:edit' when arrow key %s is pressed and element is in edit mode",
async (key) => {
const { wrapper } = setup({
const { wrapper } = setupWrapper({
isEditMode: true,
});

Expand All @@ -386,7 +456,7 @@ describe("LinkContentElement", () => {

describe("link element menu", () => {
it("should render link element menu", () => {
const { wrapper } = setup({
const { wrapper } = setupWrapper({
isEditMode: true,
});

Expand All @@ -396,7 +466,7 @@ describe("LinkContentElement", () => {
});

it("should emit 'move-down:edit' event when move down menu item is clicked", async () => {
const { wrapper } = setup({
const { wrapper } = setupWrapper({
isEditMode: true,
});

Expand All @@ -407,7 +477,7 @@ describe("LinkContentElement", () => {
});

it("should emit 'move-up:edit' event when move up menu item is clicked", async () => {
const { wrapper } = setup({
const { wrapper } = setupWrapper({
isEditMode: true,
});

Expand All @@ -418,7 +488,7 @@ describe("LinkContentElement", () => {
});

it("should emit 'delete:element' event when delete menu item is clicked", async () => {
const { wrapper } = setup({
const { wrapper } = setupWrapper({
isEditMode: true,
});

Expand All @@ -432,7 +502,10 @@ describe("LinkContentElement", () => {

describe("onCreateUrl", () => {
it("should request meta tags for the given url", async () => {
const { wrapper } = setup({ isEditMode: true, isDetailView: false });
const { wrapper } = setupWrapper({
isEditMode: true,
isDetailView: false,
});

const component = wrapper.getComponent(LinkContentElementCreate);
component.vm.$emit(
Expand All @@ -445,7 +518,10 @@ describe("LinkContentElement", () => {

describe("when no protocol was provided", () => {
it("should add https-protocol", async () => {
const { wrapper } = setup({ isEditMode: true, isDetailView: false });
const { wrapper } = setupWrapper({
isEditMode: true,
isDetailView: false,
});
const url = "abc.de/my-article";

const component = wrapper.getComponent(LinkContentElementCreate);
Expand All @@ -461,7 +537,7 @@ describe("LinkContentElement", () => {
describe("when url was provided", () => {
describe("when imageUrl was in metaTags", () => {
it("should create a preview image", async () => {
const { wrapper } = setup({
const { wrapper } = setupWrapper({
isEditMode: true,
isDetailView: false,
});
Expand Down Expand Up @@ -493,7 +569,7 @@ describe("LinkContentElement", () => {
it("should sanitize the url", async () => {
const VALID_UNSANITIZED_URL =
"&#104;&#116;&#116;&#112;&#115;&#0000058//&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;";
const { wrapper } = setup({
const { wrapper } = setupWrapper({
content: linkElementContentFactory.build({
url: VALID_UNSANITIZED_URL,
}),
Expand All @@ -508,7 +584,7 @@ describe("LinkContentElement", () => {
it("should sanitize a javascript-url", async () => {
const INVALID_UNSANITIZED_URL =
"javascript" + ":" + "alert(document.domain)";
const { wrapper } = setup({
const { wrapper } = setupWrapper({
content: linkElementContentFactory.build({
url: INVALID_UNSANITIZED_URL,
}),
Expand All @@ -522,7 +598,7 @@ describe("LinkContentElement", () => {

it("should display the hostname ", async () => {
const INVALID_UNSANITIZED_URL = "https://de.wikipedia.org/dachs";
const { wrapper } = setup({
const { wrapper } = setupWrapper({
content: linkElementContentFactory.build({
url: INVALID_UNSANITIZED_URL,
}),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<v-card
class="mb-4"
target="_blank"
:target="target"
data-testid="board-link-element"
:class="{ 'd-none': isHidden }"
:variant="outlined"
Expand Down Expand Up @@ -55,7 +55,7 @@ import {
KebabMenuActionMoveDown,
KebabMenuActionMoveUp,
} from "@ui-kebab-menu";
import { computed, PropType, ref, toRef } from "vue";
import { computed, ComputedRef, PropType, ref, toRef } from "vue";
import { useI18n } from "vue-i18n";
import { useMetaTagExtractorApi } from "../composables/MetaTagExtractorApi.composable";
import { usePreviewGenerator } from "../composables/PreviewGenerator.composable";
Expand Down Expand Up @@ -104,6 +104,21 @@ const sanitizedUrl = computed(() =>
props.element.content.url ? sanitizeUrl(props.element.content.url) : ""
);
const target: ComputedRef<string> = computed(() => {
if (props.element.content.url) {
const url = new URL(sanitizedUrl.value);
if (
url.host === window.location.host &&
url.pathname === window.location.pathname
) {
return "_self";
}
}
return "_blank";
});
const isCreating = computed(
() => props.isEditMode && !computedElement.value.content.url
);
Expand All @@ -123,9 +138,11 @@ const onCreateUrl = async (originalUrl: string) => {
const validUrl = ensureProtocolIncluded(originalUrl);
const { url, title, description, originalImageUrl } =
await getMetaTags(validUrl);
modelValue.value.url = url;
modelValue.value.title = title;
modelValue.value.description = description;
if (originalImageUrl) {
modelValue.value.imageUrl = await createPreviewImage(originalImageUrl);
}
Expand Down
2 changes: 1 addition & 1 deletion src/modules/feature/board/board/Board.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ describe("Board", () => {
await nextTick();

expect(domElementMock.scrollIntoView).toHaveBeenCalledWith({
block: "start",
block: "center",
inline: "center",
});
expect(domElementMock.focus).toHaveBeenCalled();
Expand Down
Loading

0 comments on commit 0c18e34

Please sign in to comment.