Merge branch 'new-vue-components-tested' into 'master'
Added new vue components tested See merge request framasoft/mobilizon!739
This commit is contained in:
commit
b0ab0af9ea
|
@ -26,9 +26,12 @@
|
|||
</p>
|
||||
</div>
|
||||
<div class="send-comment">
|
||||
<b-button native-type="submit" type="is-primary">{{
|
||||
$t("Post a comment")
|
||||
}}</b-button>
|
||||
<b-button
|
||||
native-type="submit"
|
||||
type="is-primary"
|
||||
class="comment-button-submit"
|
||||
>{{ $t("Post a comment") }}</b-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
@ -37,6 +40,9 @@
|
|||
$t("The organiser has chosen to close comments.")
|
||||
}}</b-notification>
|
||||
<transition name="comment-empty-list" mode="out-in">
|
||||
<p v-if="$apollo.queries.comments.loading" class="loading">
|
||||
{{ $t("Loading…") }}
|
||||
</p>
|
||||
<transition-group
|
||||
name="comment-list"
|
||||
v-if="comments.length"
|
||||
|
@ -326,7 +332,7 @@ export default class CommentTree extends Vue {
|
|||
}
|
||||
|
||||
get isAbleToComment(): boolean {
|
||||
if (this.currentActor.id) {
|
||||
if (this.currentActor && this.currentActor.id) {
|
||||
return this.areCommentsClosed || this.isEventOrganiser;
|
||||
}
|
||||
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