forked from potsda.mn/mobilizon
Added new vue components tested
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
parent
c1c9f421e0
commit
d88427f816
|
@ -26,9 +26,12 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="send-comment">
|
<div class="send-comment">
|
||||||
<b-button native-type="submit" type="is-primary">{{
|
<b-button
|
||||||
$t("Post a comment")
|
native-type="submit"
|
||||||
}}</b-button>
|
type="is-primary"
|
||||||
|
class="comment-button-submit"
|
||||||
|
>{{ $t("Post a comment") }}</b-button
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
|
@ -37,6 +40,9 @@
|
||||||
$t("The organiser has chosen to close comments.")
|
$t("The organiser has chosen to close comments.")
|
||||||
}}</b-notification>
|
}}</b-notification>
|
||||||
<transition name="comment-empty-list" mode="out-in">
|
<transition name="comment-empty-list" mode="out-in">
|
||||||
|
<p v-if="$apollo.queries.comments.loading" class="loading">
|
||||||
|
{{ $t("Loading…") }}
|
||||||
|
</p>
|
||||||
<transition-group
|
<transition-group
|
||||||
name="comment-list"
|
name="comment-list"
|
||||||
v-if="comments.length"
|
v-if="comments.length"
|
||||||
|
@ -326,7 +332,7 @@ export default class CommentTree extends Vue {
|
||||||
}
|
}
|
||||||
|
|
||||||
get isAbleToComment(): boolean {
|
get isAbleToComment(): boolean {
|
||||||
if (this.currentActor.id) {
|
if (this.currentActor && this.currentActor.id) {
|
||||||
return this.areCommentsClosed || this.isEventOrganiser;
|
return this.areCommentsClosed || this.isEventOrganiser;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
157
js/tests/unit/specs/components/Comment/CommentTree.spec.ts
Normal file
157
js/tests/unit/specs/components/Comment/CommentTree.spec.ts
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
import { config, createLocalVue, shallowMount, Wrapper } from "@vue/test-utils";
|
||||||
|
import CommentTree from "@/components/Comment/CommentTree.vue";
|
||||||
|
import Buefy from "buefy";
|
||||||
|
import { InMemoryCache } from "apollo-cache-inmemory";
|
||||||
|
import {
|
||||||
|
createMockClient,
|
||||||
|
MockApolloClient,
|
||||||
|
RequestHandler,
|
||||||
|
} from "mock-apollo-client";
|
||||||
|
import buildCurrentUserResolver from "@/apollo/user";
|
||||||
|
import VueApollo from "vue-apollo";
|
||||||
|
import { COMMENTS_THREADS, CREATE_COMMENT_FROM_EVENT } from "@/graphql/comment";
|
||||||
|
import { CommentModeration } from "@/types/enums";
|
||||||
|
import { IEvent } from "@/types/event.model";
|
||||||
|
import {
|
||||||
|
eventCommentThreadsMock,
|
||||||
|
newCommentForEventMock,
|
||||||
|
newCommentForEventResponse,
|
||||||
|
} from "../../mocks/event";
|
||||||
|
|
||||||
|
const localVue = createLocalVue();
|
||||||
|
localVue.use(Buefy);
|
||||||
|
localVue.use(VueApollo);
|
||||||
|
config.mocks.$t = (key: string): string => key;
|
||||||
|
|
||||||
|
const eventData = {
|
||||||
|
id: "1",
|
||||||
|
uuid: "e37910ea-fd5a-4756-7634-00971f3f4107",
|
||||||
|
options: {
|
||||||
|
commentModeration: CommentModeration.ALLOW_ALL,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
describe("CommentTree", () => {
|
||||||
|
let wrapper: Wrapper<Vue>;
|
||||||
|
let mockClient: MockApolloClient;
|
||||||
|
let apolloProvider;
|
||||||
|
let requestHandlers: Record<string, RequestHandler>;
|
||||||
|
|
||||||
|
const generateWrapper = (handlers = {}, baseData = {}) => {
|
||||||
|
const cache = new InMemoryCache({ addTypename: false });
|
||||||
|
|
||||||
|
mockClient = createMockClient({
|
||||||
|
cache,
|
||||||
|
resolvers: buildCurrentUserResolver(cache),
|
||||||
|
});
|
||||||
|
|
||||||
|
requestHandlers = {
|
||||||
|
eventCommentThreadsQueryHandler: jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValue(eventCommentThreadsMock),
|
||||||
|
createCommentForEventMutationHandler: jest
|
||||||
|
.fn()
|
||||||
|
.mockResolvedValue(newCommentForEventResponse),
|
||||||
|
...handlers,
|
||||||
|
};
|
||||||
|
|
||||||
|
mockClient.setRequestHandler(
|
||||||
|
COMMENTS_THREADS,
|
||||||
|
requestHandlers.eventCommentThreadsQueryHandler
|
||||||
|
);
|
||||||
|
mockClient.setRequestHandler(
|
||||||
|
CREATE_COMMENT_FROM_EVENT,
|
||||||
|
requestHandlers.createCommentForEventMutationHandler
|
||||||
|
);
|
||||||
|
|
||||||
|
apolloProvider = new VueApollo({
|
||||||
|
defaultClient: mockClient,
|
||||||
|
});
|
||||||
|
|
||||||
|
wrapper = shallowMount(CommentTree, {
|
||||||
|
localVue,
|
||||||
|
apolloProvider,
|
||||||
|
propsData: {
|
||||||
|
event: { ...eventData },
|
||||||
|
},
|
||||||
|
stubs: ["editor"],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentActor: {
|
||||||
|
id: "76",
|
||||||
|
},
|
||||||
|
...baseData,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
it("renders a comment tree", async () => {
|
||||||
|
generateWrapper();
|
||||||
|
|
||||||
|
expect(wrapper.findComponent({ name: "b-notification" }).text()).toBe(
|
||||||
|
"The organiser has chosen to close comments."
|
||||||
|
);
|
||||||
|
expect(wrapper.find(".loading").text()).toBe("Loading…");
|
||||||
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders a comment tree", async () => {
|
||||||
|
generateWrapper();
|
||||||
|
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
await wrapper.vm.$nextTick(); // because of the <transition>
|
||||||
|
|
||||||
|
expect(wrapper.exists()).toBe(true);
|
||||||
|
expect(requestHandlers.eventCommentThreadsQueryHandler).toHaveBeenCalled();
|
||||||
|
expect(wrapper.vm.$apollo.queries.comments).toBeTruthy();
|
||||||
|
expect(wrapper.find(".loading").exists()).toBe(false);
|
||||||
|
expect(wrapper.findAll(".comment-list .root-comment").length).toBe(2);
|
||||||
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders the form if we can comment", async () => {
|
||||||
|
generateWrapper(
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
newComment: {
|
||||||
|
text: newCommentForEventMock.text,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
wrapper.setData({
|
||||||
|
currentActor: {
|
||||||
|
id: "67",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
await wrapper.vm.$nextTick(); // because of the <transition>
|
||||||
|
|
||||||
|
expect(wrapper.find("form.new-comment").isVisible()).toBe(true);
|
||||||
|
expect(wrapper.findAll(".comment-list .root-comment").length).toBe(2);
|
||||||
|
|
||||||
|
wrapper.find("form.new-comment").trigger("submit");
|
||||||
|
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
expect(
|
||||||
|
requestHandlers.createCommentForEventMutationHandler
|
||||||
|
).toHaveBeenCalledWith({
|
||||||
|
...newCommentForEventMock,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (mockClient) {
|
||||||
|
const cachedData = mockClient.cache.readQuery<{ event: IEvent }>({
|
||||||
|
query: COMMENTS_THREADS,
|
||||||
|
variables: {
|
||||||
|
eventUUID: eventData.uuid,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (cachedData) {
|
||||||
|
const { event } = cachedData;
|
||||||
|
|
||||||
|
expect(event.comments).toHaveLength(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`CommentTree renders a comment tree 1`] = `
|
||||||
|
<div>
|
||||||
|
<b-notification-stub active="true" duration="2000" animation="fade">The organiser has chosen to close comments.</b-notification-stub>
|
||||||
|
<transition-stub name="comment-empty-list" mode="out-in">
|
||||||
|
<p class="loading">
|
||||||
|
Loading…
|
||||||
|
</p>
|
||||||
|
<!---->
|
||||||
|
</transition-stub>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`CommentTree renders a comment tree 2`] = `
|
||||||
|
<div>
|
||||||
|
<b-notification-stub active="true" duration="2000" animation="fade">The organiser has chosen to close comments.</b-notification-stub>
|
||||||
|
<transition-stub name="comment-empty-list" mode="out-in">
|
||||||
|
<!---->
|
||||||
|
<transition-group-stub tag="ul" name="comment-list" class="comment-list">
|
||||||
|
<comment-stub comment="[object Object]" event="[object Object]" class="root-comment"></comment-stub>
|
||||||
|
<comment-stub comment="[object Object]" event="[object Object]" class="root-comment"></comment-stub>
|
||||||
|
</transition-group-stub>
|
||||||
|
</transition-stub>
|
||||||
|
</div>
|
||||||
|
`;
|
62
js/tests/unit/specs/components/Report/ReportCard.spec.ts
Normal file
62
js/tests/unit/specs/components/Report/ReportCard.spec.ts
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
import { config, createLocalVue, mount } from "@vue/test-utils";
|
||||||
|
import ReportCard from "@/components/Report/ReportCard.vue";
|
||||||
|
import Buefy from "buefy";
|
||||||
|
import { ActorType } from "@/types/enums";
|
||||||
|
|
||||||
|
const localVue = createLocalVue();
|
||||||
|
localVue.use(Buefy);
|
||||||
|
config.mocks.$t = (key: string): string => key;
|
||||||
|
|
||||||
|
const reportData = {
|
||||||
|
id: "1",
|
||||||
|
content: "My content",
|
||||||
|
insertedAt: "2020-12-02T09:01:20.873Z",
|
||||||
|
reporter: {
|
||||||
|
preferredUsername: "author",
|
||||||
|
domain: null,
|
||||||
|
name: "Reporter of Things",
|
||||||
|
type: ActorType.PERSON,
|
||||||
|
},
|
||||||
|
reported: {
|
||||||
|
preferredUsername: "my-awesome-group",
|
||||||
|
domain: null,
|
||||||
|
name: "My Awesome Group",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateWrapper = (customReportData: Record<string, unknown> = {}) => {
|
||||||
|
return mount(ReportCard, {
|
||||||
|
localVue,
|
||||||
|
propsData: {
|
||||||
|
report: { ...reportData, ...customReportData },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("ReportCard", () => {
|
||||||
|
it("renders report card with basic informations", () => {
|
||||||
|
const wrapper = generateWrapper();
|
||||||
|
|
||||||
|
expect(wrapper.find(".media-content .title").text()).toBe(
|
||||||
|
reportData.reported.name
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(wrapper.find(".media-content .subtitle").text()).toBe(
|
||||||
|
`@${reportData.reported.preferredUsername}`
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(wrapper.find(".is-one-quarter-desktop span").text()).toBe(
|
||||||
|
`Reported by {reporter}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders report card with with a remote reporter", () => {
|
||||||
|
const wrapper = generateWrapper({
|
||||||
|
reporter: { domain: "somewhere.else", type: ActorType.APPLICATION },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.find(".is-one-quarter-desktop span").text()).toBe(
|
||||||
|
"Reported by someone on {domain}"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
130
js/tests/unit/specs/components/Report/ReportModal.spec.ts
Normal file
130
js/tests/unit/specs/components/Report/ReportModal.spec.ts
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
import { config, createLocalVue, mount } from "@vue/test-utils";
|
||||||
|
import ReportModal from "@/components/Report/ReportModal.vue";
|
||||||
|
import Buefy from "buefy";
|
||||||
|
|
||||||
|
const localVue = createLocalVue();
|
||||||
|
localVue.use(Buefy);
|
||||||
|
config.mocks.$t = (key: string): string => key;
|
||||||
|
|
||||||
|
const propsData = {
|
||||||
|
onConfirm: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateWrapper = (customPropsData: Record<string, unknown> = {}) => {
|
||||||
|
return mount(ReportModal, {
|
||||||
|
localVue,
|
||||||
|
propsData: {
|
||||||
|
...propsData,
|
||||||
|
...customPropsData,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.resetAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("ReportModal", () => {
|
||||||
|
it("renders report modal with basic informations and submits it", async () => {
|
||||||
|
const wrapper = generateWrapper();
|
||||||
|
|
||||||
|
expect(wrapper.find(".modal-card-head").exists()).toBe(false);
|
||||||
|
|
||||||
|
expect(wrapper.find(".media-content").text()).not.toContain(
|
||||||
|
"The content came from another server. Transfer an anonymous copy of the report?"
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
wrapper.find("footer.modal-card-foot button:first-child").text()
|
||||||
|
).toBe("Cancel");
|
||||||
|
|
||||||
|
const submit = wrapper.find("footer.modal-card-foot button.is-primary");
|
||||||
|
|
||||||
|
expect(submit.text()).toBe("Send the report");
|
||||||
|
|
||||||
|
const textarea = wrapper.find("textarea");
|
||||||
|
textarea.setValue("some comment with my report");
|
||||||
|
|
||||||
|
submit.trigger("click");
|
||||||
|
|
||||||
|
await localVue.nextTick();
|
||||||
|
expect(wrapper.emitted().close).toBeTruthy();
|
||||||
|
|
||||||
|
expect(wrapper.vm.$props.onConfirm).toHaveBeenCalledTimes(1);
|
||||||
|
expect(wrapper.vm.$props.onConfirm).toHaveBeenCalledWith(
|
||||||
|
"some comment with my report",
|
||||||
|
false
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders report modal and shows an inline comment if it's provided", async () => {
|
||||||
|
const wrapper = generateWrapper({
|
||||||
|
comment: {
|
||||||
|
actor: { preferredUsername: "author", name: "I am the comment author" },
|
||||||
|
text: "this is my <b>comment</b> that will be reported",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const commentContainer = wrapper.find("article.media");
|
||||||
|
expect(commentContainer.find("strong").text()).toContain(
|
||||||
|
"I am the comment author"
|
||||||
|
);
|
||||||
|
expect(commentContainer.find("small").text()).toContain("author");
|
||||||
|
expect(commentContainer.find("p").html()).toContain(
|
||||||
|
"this is my <b>comment</b> that will be reported"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders report modal with with a remote content", async () => {
|
||||||
|
const wrapper = generateWrapper({ outsideDomain: "somewhere.else" });
|
||||||
|
|
||||||
|
expect(wrapper.find(".media-content").text()).toContain(
|
||||||
|
"The content came from another server. Transfer an anonymous copy of the report?"
|
||||||
|
);
|
||||||
|
|
||||||
|
const submit = wrapper.find("footer.modal-card-foot button.is-primary");
|
||||||
|
submit.trigger("click");
|
||||||
|
await localVue.nextTick();
|
||||||
|
|
||||||
|
expect(wrapper.vm.$props.onConfirm).toHaveBeenCalledTimes(1);
|
||||||
|
expect(wrapper.vm.$props.onConfirm).toHaveBeenCalledWith("", false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders report modal with with a remote content and accept to forward", async () => {
|
||||||
|
const wrapper = generateWrapper({ outsideDomain: "somewhere.else" });
|
||||||
|
|
||||||
|
expect(wrapper.find(".media-content").text()).toContain(
|
||||||
|
"The content came from another server. Transfer an anonymous copy of the report?"
|
||||||
|
);
|
||||||
|
|
||||||
|
const switchButton = wrapper.find('input[type="checkbox"]');
|
||||||
|
switchButton.trigger("click");
|
||||||
|
|
||||||
|
const submit = wrapper.find("footer.modal-card-foot button.is-primary");
|
||||||
|
submit.trigger("click");
|
||||||
|
await localVue.nextTick();
|
||||||
|
|
||||||
|
expect(wrapper.vm.$props.onConfirm).toHaveBeenCalledTimes(1);
|
||||||
|
expect(wrapper.vm.$props.onConfirm).toHaveBeenCalledWith("", true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders report modal custom title and buttons", async () => {
|
||||||
|
const wrapper = generateWrapper({
|
||||||
|
title: "want to report something?",
|
||||||
|
cancelText: "nah",
|
||||||
|
confirmText: "report!",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.find(".modal-card-head .modal-card-title").text()).toBe(
|
||||||
|
"want to report something?"
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
wrapper.find("footer.modal-card-foot button:first-child").text()
|
||||||
|
).toBe("nah");
|
||||||
|
|
||||||
|
expect(
|
||||||
|
wrapper.find("footer.modal-card-foot button.is-primary").text()
|
||||||
|
).toBe("report!");
|
||||||
|
});
|
||||||
|
});
|
95
js/tests/unit/specs/mocks/event.ts
Normal file
95
js/tests/unit/specs/mocks/event.ts
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
export const eventCommentThreadsMock = {
|
||||||
|
data: {
|
||||||
|
event: {
|
||||||
|
__typename: "Event",
|
||||||
|
id: "1",
|
||||||
|
uuid: "f37910ea-fd5a-4756-9679-00971f3f4106",
|
||||||
|
comments: [
|
||||||
|
{
|
||||||
|
__typename: "Comment",
|
||||||
|
id: "2",
|
||||||
|
uuid: "e37910ea-fd5a-4756-9679-00971f3f4107",
|
||||||
|
url:
|
||||||
|
"https://some-instance.tld/comments/e37910ea-fd5a-4756-9679-00971f3f4107",
|
||||||
|
text: "my comment text",
|
||||||
|
local: true,
|
||||||
|
visibility: "PUBLIC",
|
||||||
|
totalReplies: 5,
|
||||||
|
updatedAt: "2020-12-03T09:02:00Z",
|
||||||
|
actor: {
|
||||||
|
avatar: {
|
||||||
|
id: "78",
|
||||||
|
url: "http://someavatar.url.me",
|
||||||
|
},
|
||||||
|
id: "89",
|
||||||
|
domain: null,
|
||||||
|
preferredUsername: "someauthor",
|
||||||
|
name: "Some author",
|
||||||
|
summary: "I am the senate",
|
||||||
|
},
|
||||||
|
deletedAt: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
__typename: "Comment",
|
||||||
|
id: "29",
|
||||||
|
uuid: "e37910ea-fd5a-4756-9679-01171f3f4107",
|
||||||
|
url:
|
||||||
|
"https://some-instance.tld/comments/e37910ea-fd5a-4756-9679-01171f3f4107",
|
||||||
|
text: "a second comment",
|
||||||
|
local: true,
|
||||||
|
visibility: "PUBLIC",
|
||||||
|
totalReplies: 0,
|
||||||
|
updatedAt: "2020-12-03T11:02:00Z",
|
||||||
|
actor: {
|
||||||
|
avatar: {
|
||||||
|
id: "78",
|
||||||
|
url: "http://someavatar.url.me",
|
||||||
|
},
|
||||||
|
id: "89",
|
||||||
|
domain: null,
|
||||||
|
preferredUsername: "someauthor",
|
||||||
|
name: "Some author",
|
||||||
|
summary: "I am the senate",
|
||||||
|
},
|
||||||
|
deletedAt: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const newCommentForEventMock = {
|
||||||
|
eventId: "1",
|
||||||
|
text: "my new comment",
|
||||||
|
inReplyToCommentId: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const newCommentForEventResponse = {
|
||||||
|
data: {
|
||||||
|
createComment: {
|
||||||
|
id: "79",
|
||||||
|
uuid: "e37910ea-fd5a-4756-9679-01171f3f4444",
|
||||||
|
url:
|
||||||
|
"https://some-instance.tld/comments/e37910ea-fd5a-4756-9679-01171f3f4444",
|
||||||
|
text: newCommentForEventMock.text,
|
||||||
|
local: true,
|
||||||
|
visibility: "PUBLIC",
|
||||||
|
totalReplies: 0,
|
||||||
|
updatedAt: "2020-12-03T13:02:00Z",
|
||||||
|
originComment: null,
|
||||||
|
inReplyToComment: null,
|
||||||
|
actor: {
|
||||||
|
avatar: {
|
||||||
|
id: "78",
|
||||||
|
url: "http://someavatar.url.me",
|
||||||
|
},
|
||||||
|
id: "89",
|
||||||
|
domain: null,
|
||||||
|
preferredUsername: "someauthor",
|
||||||
|
name: "Some author",
|
||||||
|
summary: "I am the senate",
|
||||||
|
},
|
||||||
|
deletedAt: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
Loading…
Reference in a new issue