Migrate to Vue 3 and Vite
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
16
js/tests/unit/setup.ts
Normal file
16
js/tests/unit/setup.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import "./specs/mocks/matchMedia";
|
||||
import { config } from "@vue/test-utils";
|
||||
import { createHead } from "@vueuse/head";
|
||||
import { createI18n } from "vue-i18n";
|
||||
import en_US from "@/i18n/en_US.json";
|
||||
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
messages: { en_US },
|
||||
locale: "en_US",
|
||||
});
|
||||
|
||||
const head = createHead();
|
||||
|
||||
config.global.plugins.push(head);
|
||||
config.global.plugins.push(i18n);
|
||||
@@ -1,50 +0,0 @@
|
||||
import { config, createLocalVue, mount } from "@vue/test-utils";
|
||||
import { routes } from "@/router";
|
||||
import App from "@/App.vue";
|
||||
import VueRouter from "vue-router";
|
||||
import Buefy from "buefy";
|
||||
import flushPromises from "flush-promises";
|
||||
import VueAnnouncer from "@vue-a11y/announcer";
|
||||
import VueSkipTo from "@vue-a11y/skip-to";
|
||||
|
||||
const localVue = createLocalVue();
|
||||
config.mocks.$t = (key: string): string => key;
|
||||
localVue.use(VueRouter);
|
||||
localVue.use(Buefy);
|
||||
localVue.use(VueAnnouncer);
|
||||
localVue.use(VueSkipTo);
|
||||
|
||||
describe("routing", () => {
|
||||
test("Homepage", async () => {
|
||||
const router = new VueRouter({ routes, mode: "history" });
|
||||
const wrapper = mount(App, {
|
||||
localVue,
|
||||
router,
|
||||
stubs: {
|
||||
NavBar: true,
|
||||
"mobilizon-footer": true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.html()).toContain('<div id="homepage">');
|
||||
});
|
||||
|
||||
test("About", async () => {
|
||||
const router = new VueRouter({ routes, mode: "history" });
|
||||
const wrapper = mount(App, {
|
||||
localVue,
|
||||
router,
|
||||
stubs: {
|
||||
NavBar: true,
|
||||
"mobilizon-footer": true,
|
||||
},
|
||||
});
|
||||
|
||||
router.push("/about");
|
||||
await flushPromises();
|
||||
expect(wrapper.vm.$route.path).toBe("/about/instance");
|
||||
expect(wrapper.html()).toContain(
|
||||
'<a href="/about/instance" aria-current="page"'
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,12 +1,10 @@
|
||||
import { config, createLocalVue, shallowMount, Wrapper } from "@vue/test-utils";
|
||||
import { config, shallowMount, VueWrapper } from "@vue/test-utils";
|
||||
import CommentTree from "@/components/Comment/CommentTree.vue";
|
||||
import Buefy from "buefy";
|
||||
import {
|
||||
createMockClient,
|
||||
MockApolloClient,
|
||||
RequestHandler,
|
||||
} from "mock-apollo-client";
|
||||
import VueApollo from "@vue/apollo-option";
|
||||
import {
|
||||
COMMENTS_THREADS_WITH_REPLIES,
|
||||
CREATE_COMMENT_FROM_EVENT,
|
||||
@@ -21,10 +19,20 @@ import {
|
||||
} from "../../mocks/event";
|
||||
import flushPromises from "flush-promises";
|
||||
import { defaultResolvers } from "../../common";
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Buefy);
|
||||
localVue.use(VueApollo);
|
||||
config.mocks.$t = (key: string): string => key;
|
||||
import { afterEach, describe, vi, it, expect, beforeEach } from "vitest";
|
||||
import { DefaultApolloClient } from "@vue/apollo-composable";
|
||||
import Oruga from "@oruga-ui/oruga-next";
|
||||
import { notifierPlugin } from "@/plugins/notifier";
|
||||
import { InMemoryCache } from "@apollo/client/cache";
|
||||
import { createRouter, createWebHistory, Router } from "vue-router";
|
||||
import { routes } from "@/router";
|
||||
import { dialogPlugin } from "@/plugins/dialog";
|
||||
|
||||
config.global.plugins.push(Oruga);
|
||||
config.global.plugins.push(notifierPlugin);
|
||||
config.global.plugins.push(dialogPlugin);
|
||||
|
||||
let router: Router;
|
||||
|
||||
const eventData = {
|
||||
id: "1",
|
||||
@@ -34,21 +42,23 @@ const eventData = {
|
||||
},
|
||||
};
|
||||
describe("CommentTree", () => {
|
||||
let wrapper: Wrapper<Vue>;
|
||||
let wrapper: VueWrapper;
|
||||
let mockClient: MockApolloClient | null;
|
||||
let apolloProvider;
|
||||
let requestHandlers: Record<string, RequestHandler>;
|
||||
|
||||
const generateWrapper = (handlers = {}, baseData = {}) => {
|
||||
const generateWrapper = (handlers = {}, extraProps = {}) => {
|
||||
const cache = new InMemoryCache({ addTypename: true });
|
||||
|
||||
mockClient = createMockClient({
|
||||
cache,
|
||||
resolvers: defaultResolvers,
|
||||
});
|
||||
|
||||
requestHandlers = {
|
||||
eventCommentThreadsQueryHandler: jest
|
||||
eventCommentThreadsQueryHandler: vi
|
||||
.fn()
|
||||
.mockResolvedValue(eventCommentThreadsMock),
|
||||
createCommentForEventMutationHandler: jest
|
||||
createCommentForEventMutationHandler: vi
|
||||
.fn()
|
||||
.mockResolvedValue(newCommentForEventResponse),
|
||||
...handlers,
|
||||
@@ -62,36 +72,39 @@ describe("CommentTree", () => {
|
||||
CREATE_COMMENT_FROM_EVENT,
|
||||
requestHandlers.createCommentForEventMutationHandler
|
||||
);
|
||||
apolloProvider = new VueApollo({
|
||||
defaultClient: mockClient,
|
||||
});
|
||||
|
||||
wrapper = shallowMount(CommentTree, {
|
||||
localVue,
|
||||
apolloProvider,
|
||||
propsData: {
|
||||
props: {
|
||||
event: { ...eventData },
|
||||
...extraProps,
|
||||
},
|
||||
stubs: ["editor"],
|
||||
data() {
|
||||
return {
|
||||
...baseData,
|
||||
};
|
||||
global: {
|
||||
provide: {
|
||||
[DefaultApolloClient]: mockClient,
|
||||
},
|
||||
plugins: [router],
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: routes,
|
||||
});
|
||||
|
||||
// await router.isReady();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockClient = null;
|
||||
requestHandlers = {};
|
||||
apolloProvider = null;
|
||||
wrapper.destroy();
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
it("renders a loading comment tree", async () => {
|
||||
generateWrapper();
|
||||
|
||||
expect(wrapper.find(".loading").text()).toBe("Loading comments…");
|
||||
expect(wrapper.find("p.text-center").text()).toBe("Loading comments…");
|
||||
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
@@ -99,15 +112,14 @@ describe("CommentTree", () => {
|
||||
it("renders a comment tree with comments", async () => {
|
||||
generateWrapper();
|
||||
|
||||
await flushPromises();
|
||||
|
||||
expect(wrapper.exists()).toBe(true);
|
||||
expect(
|
||||
requestHandlers.eventCommentThreadsQueryHandler
|
||||
).toHaveBeenCalledWith({ eventUUID: eventData.uuid });
|
||||
expect(wrapper.vm.$apollo.queries.comments).toBeTruthy();
|
||||
expect(wrapper.find(".loading").exists()).toBe(false);
|
||||
expect(wrapper.findAll(".comment-list .root-comment").length).toBe(2);
|
||||
await flushPromises();
|
||||
expect(wrapper.find("p.text-center").exists()).toBe(false);
|
||||
|
||||
expect(wrapper.findAllComponents("comment-stub").length).toBe(2);
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
@@ -117,18 +129,20 @@ describe("CommentTree", () => {
|
||||
{
|
||||
newComment: {
|
||||
text: newCommentForEventMock.text,
|
||||
isAnnouncement: false,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
await flushPromises();
|
||||
|
||||
expect(wrapper.find("form.new-comment").isVisible()).toBe(true);
|
||||
expect(wrapper.findAll(".comment-list .root-comment").length).toBe(2);
|
||||
expect(wrapper.find("form").isVisible()).toBe(true);
|
||||
expect(wrapper.findAllComponents("comment-stub").length).toBe(2);
|
||||
wrapper.getComponent({ ref: "commenteditor" });
|
||||
|
||||
wrapper.find("form.new-comment").trigger("submit");
|
||||
wrapper.find("form").trigger("submit");
|
||||
|
||||
await wrapper.vm.$nextTick();
|
||||
await flushPromises();
|
||||
expect(
|
||||
requestHandlers.createCommentForEventMutationHandler
|
||||
).toHaveBeenCalledWith({
|
||||
@@ -152,7 +166,7 @@ describe("CommentTree", () => {
|
||||
|
||||
it("renders an empty comment tree", async () => {
|
||||
generateWrapper({
|
||||
eventCommentThreadsQueryHandler: jest
|
||||
eventCommentThreadsQueryHandler: vi
|
||||
.fn()
|
||||
.mockResolvedValue(eventNoCommentThreadsMock),
|
||||
});
|
||||
@@ -162,9 +176,7 @@ describe("CommentTree", () => {
|
||||
requestHandlers.eventCommentThreadsQueryHandler
|
||||
).toHaveBeenCalledWith({ eventUUID: eventData.uuid });
|
||||
|
||||
expect(wrapper.findComponent({ name: "EmptyContent" }).text()).toBe(
|
||||
"No comments yet"
|
||||
);
|
||||
expect(wrapper.findComponent({ name: "EmptyContent" }).exists());
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,73 +1,67 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`CommentTree renders a comment tree with comments 1`] = `
|
||||
<div>
|
||||
<form class="new-comment">
|
||||
<!---->
|
||||
<article class="media">
|
||||
<figure class="media-left">
|
||||
<identity-picker-wrapper-stub value="[object Object]"></identity-picker-wrapper-stub>
|
||||
exports[`CommentTree > renders a comment tree with comments 1`] = `
|
||||
"<div data-v-1d76124d=\\"\\">
|
||||
<form class=\\"\\" data-v-1d76124d=\\"\\">
|
||||
<!--v-if-->
|
||||
<article class=\\"flex flex-wrap items-start gap-2\\" data-v-1d76124d=\\"\\">
|
||||
<figure class=\\"\\" data-v-1d76124d=\\"\\">
|
||||
<identity-picker-wrapper-stub modelvalue=\\"[object Object]\\" inline=\\"false\\" masked=\\"false\\" data-v-1d76124d=\\"\\"></identity-picker-wrapper-stub>
|
||||
</figure>
|
||||
<div class="media-content">
|
||||
<div class="field">
|
||||
<div class="field">
|
||||
<p class="control">
|
||||
<editor-stub mode="comment" aria-label="Comment body" value=""></editor-stub>
|
||||
</p>
|
||||
<!---->
|
||||
<div class=\\"flex-1\\" data-v-1d76124d=\\"\\">
|
||||
<div class=\\"flex flex-col gap-2\\" data-v-1d76124d=\\"\\">
|
||||
<div class=\\"editor-wrapper\\" data-v-1d76124d=\\"\\">
|
||||
<editor-stub currentactor=\\"[object Object]\\" mode=\\"comment\\" modelvalue=\\"\\" aria-label=\\"Comment body\\" data-v-1d76124d=\\"\\"></editor-stub>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
<!---->
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</div>
|
||||
<div class="send-comment">
|
||||
<b-button-stub type="is-primary" iconleft="send" nativetype="submit" tag="button" class="comment-button-submit">Send</b-button-stub>
|
||||
<div class=\\"\\" data-v-1d76124d=\\"\\">
|
||||
<o-button-stub variant=\\"primary\\" iconleft=\\"send\\" rounded=\\"false\\" outlined=\\"false\\" expanded=\\"false\\" inverted=\\"false\\" nativetype=\\"submit\\" tag=\\"button\\" disabled=\\"false\\" iconboth=\\"false\\" data-v-1d76124d=\\"\\"></o-button-stub>
|
||||
</div>
|
||||
</article>
|
||||
</form>
|
||||
<transition-group-stub tag="div" name="comment-empty-list">
|
||||
<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 data-v-1d76124d=\\"\\">
|
||||
<transition-group-stub data-v-1d76124d=\\"\\">
|
||||
<comment-stub comment=\\"[object Object]\\" event=\\"[object Object]\\" currentactor=\\"[object Object]\\" rootcomment=\\"true\\" class=\\"root-comment\\" data-v-1d76124d=\\"\\"></comment-stub>
|
||||
<comment-stub comment=\\"[object Object]\\" event=\\"[object Object]\\" currentactor=\\"[object Object]\\" rootcomment=\\"true\\" class=\\"root-comment\\" data-v-1d76124d=\\"\\"></comment-stub>
|
||||
</transition-group-stub>
|
||||
</transition-group-stub>
|
||||
</div>
|
||||
</div>"
|
||||
`;
|
||||
|
||||
exports[`CommentTree renders a loading comment tree 1`] = `
|
||||
<div>
|
||||
<!---->
|
||||
<p class="loading has-text-centered">
|
||||
Loading comments…
|
||||
</p>
|
||||
</div>
|
||||
exports[`CommentTree > renders a loading comment tree 1`] = `
|
||||
"<div data-v-1d76124d=\\"\\">
|
||||
<!--v-if-->
|
||||
<p class=\\"text-center\\" data-v-1d76124d=\\"\\">Loading comments…</p>
|
||||
</div>"
|
||||
`;
|
||||
|
||||
exports[`CommentTree renders an empty comment tree 1`] = `
|
||||
<div>
|
||||
<form class="new-comment">
|
||||
<!---->
|
||||
<article class="media">
|
||||
<figure class="media-left">
|
||||
<identity-picker-wrapper-stub value="[object Object]"></identity-picker-wrapper-stub>
|
||||
exports[`CommentTree > renders an empty comment tree 1`] = `
|
||||
"<div data-v-1d76124d=\\"\\">
|
||||
<form class=\\"\\" data-v-1d76124d=\\"\\">
|
||||
<!--v-if-->
|
||||
<article class=\\"flex flex-wrap items-start gap-2\\" data-v-1d76124d=\\"\\">
|
||||
<figure class=\\"\\" data-v-1d76124d=\\"\\">
|
||||
<identity-picker-wrapper-stub modelvalue=\\"[object Object]\\" inline=\\"false\\" masked=\\"false\\" data-v-1d76124d=\\"\\"></identity-picker-wrapper-stub>
|
||||
</figure>
|
||||
<div class="media-content">
|
||||
<div class="field">
|
||||
<div class="field">
|
||||
<p class="control">
|
||||
<editor-stub mode="comment" aria-label="Comment body" value=""></editor-stub>
|
||||
</p>
|
||||
<!---->
|
||||
<div class=\\"flex-1\\" data-v-1d76124d=\\"\\">
|
||||
<div class=\\"flex flex-col gap-2\\" data-v-1d76124d=\\"\\">
|
||||
<div class=\\"editor-wrapper\\" data-v-1d76124d=\\"\\">
|
||||
<editor-stub currentactor=\\"[object Object]\\" mode=\\"comment\\" modelvalue=\\"\\" aria-label=\\"Comment body\\" data-v-1d76124d=\\"\\"></editor-stub>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
<!---->
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</div>
|
||||
<div class="send-comment">
|
||||
<b-button-stub type="is-primary" iconleft="send" nativetype="submit" tag="button" class="comment-button-submit">Send</b-button-stub>
|
||||
<div class=\\"\\" data-v-1d76124d=\\"\\">
|
||||
<o-button-stub variant=\\"primary\\" iconleft=\\"send\\" rounded=\\"false\\" outlined=\\"false\\" expanded=\\"false\\" inverted=\\"false\\" nativetype=\\"submit\\" tag=\\"button\\" disabled=\\"false\\" iconboth=\\"false\\" data-v-1d76124d=\\"\\"></o-button-stub>
|
||||
</div>
|
||||
</article>
|
||||
</form>
|
||||
<transition-group-stub tag="div" name="comment-empty-list">
|
||||
<empty-content-stub icon="comment" descriptionclasses="" inline="true"><span>No comments yet</span></empty-content-stub>
|
||||
<transition-group-stub data-v-1d76124d=\\"\\">
|
||||
<empty-content-stub icon=\\"comment\\" descriptionclasses=\\"\\" inline=\\"true\\" center=\\"false\\" data-v-1d76124d=\\"\\"></empty-content-stub>
|
||||
</transition-group-stub>
|
||||
</div>
|
||||
</div>"
|
||||
`;
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
import { config, createLocalVue, mount } from "@vue/test-utils";
|
||||
import { config, mount } from "@vue/test-utils";
|
||||
import GroupSection from "@/components/Group/GroupSection.vue";
|
||||
import Buefy from "buefy";
|
||||
import VueRouter, { Location } from "vue-router";
|
||||
import RouteName from "@/router/name";
|
||||
import { routes } from "@/router";
|
||||
import { describe, it, expect, beforeEach } from "vitest";
|
||||
import { createRouter, createWebHistory, Router } from "vue-router";
|
||||
import Oruga from "@oruga-ui/oruga-next";
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Buefy);
|
||||
config.mocks.$t = (key: string): string => key;
|
||||
localVue.use(VueRouter);
|
||||
const router = new VueRouter({ routes, mode: "history" });
|
||||
config.global.plugins.push(Oruga);
|
||||
|
||||
let router: Router;
|
||||
|
||||
beforeEach(async () => {
|
||||
router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: routes,
|
||||
});
|
||||
|
||||
// await router.isReady();
|
||||
});
|
||||
|
||||
const groupPreferredUsername = "my_group";
|
||||
const groupDomain = "remotedomain.net";
|
||||
@@ -22,7 +30,7 @@ type Props = {
|
||||
title?: string;
|
||||
icon?: string;
|
||||
privateSection?: boolean;
|
||||
route?: Location;
|
||||
route?: { name: string; params: { preferredUsername: string } };
|
||||
};
|
||||
|
||||
const baseProps: Props = {
|
||||
@@ -38,47 +46,42 @@ const baseProps: Props = {
|
||||
|
||||
const generateWrapper = (customProps: Props = {}) => {
|
||||
return mount(GroupSection, {
|
||||
localVue,
|
||||
router,
|
||||
propsData: { ...baseProps, ...customProps },
|
||||
props: { ...baseProps, ...customProps },
|
||||
slots: {
|
||||
default: `<div>${defaultSlotText}</div>`,
|
||||
create: `<router-link :to="{
|
||||
name: 'POST_CREATE',
|
||||
params: { preferredUsername: '${groupUsername}' },
|
||||
}"
|
||||
class="button is-primary"
|
||||
>{{ $t("${createSlotButtonText}") }}</router-link
|
||||
>`,
|
||||
create: `<router-link :to="{
|
||||
name: 'POST_CREATE',
|
||||
params: {
|
||||
preferredUsername: '${groupUsername}'
|
||||
}
|
||||
}"
|
||||
class="btn-primary">${createSlotButtonText}</router-link>`,
|
||||
},
|
||||
global: {
|
||||
plugins: [router],
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
describe("GroupSection", () => {
|
||||
it("renders group section with basic informations", () => {
|
||||
const wrapper = generateWrapper({});
|
||||
const wrapper = generateWrapper();
|
||||
|
||||
expect(
|
||||
wrapper
|
||||
.find(".group-section-title h2 span.icon i")
|
||||
.classes(`mdi-${baseProps.icon}`)
|
||||
).toBe(true);
|
||||
expect(wrapper.find("i.mdi").classes(`mdi-${baseProps.icon}`)).toBe(true);
|
||||
|
||||
expect(wrapper.find(".group-section-title h2 span:last-child").text()).toBe(
|
||||
baseProps.title
|
||||
expect(wrapper.find("h2").text()).toBe(baseProps.title);
|
||||
|
||||
expect(wrapper.find("a").attributes("href")).toBe(`/@${groupUsername}/p`);
|
||||
|
||||
// expect(wrapper.find(".group-section-title").classes("privateSection")).toBe(
|
||||
// true
|
||||
// );
|
||||
|
||||
expect(wrapper.find("section > div.flex-1").text()).toBe(defaultSlotText);
|
||||
expect(wrapper.find(".flex.justify-end.p-2 a").text()).toBe(
|
||||
createSlotButtonText
|
||||
);
|
||||
|
||||
expect(wrapper.find(".group-section-title a").attributes("href")).toBe(
|
||||
`/@${groupUsername}/p`
|
||||
);
|
||||
|
||||
expect(wrapper.find(".group-section-title").classes("privateSection")).toBe(
|
||||
true
|
||||
);
|
||||
|
||||
expect(wrapper.find(".main-slot div").text()).toBe(defaultSlotText);
|
||||
expect(wrapper.find(".create-slot a").text()).toBe(createSlotButtonText);
|
||||
expect(wrapper.find(".create-slot a").attributes("href")).toBe(
|
||||
expect(wrapper.find(".flex.justify-end.p-2 a").attributes("href")).toBe(
|
||||
`/@${groupUsername}/p/new`
|
||||
);
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
@@ -87,9 +90,9 @@ describe("GroupSection", () => {
|
||||
it("renders public group section", () => {
|
||||
const wrapper = generateWrapper({ privateSection: false });
|
||||
|
||||
expect(wrapper.find(".group-section-title").classes("privateSection")).toBe(
|
||||
false
|
||||
);
|
||||
// expect(wrapper.find(".group-section-title").classes("privateSection")).toBe(
|
||||
// false
|
||||
// );
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,25 +1,29 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`GroupSection renders group section with basic informations 1`] = `
|
||||
<section>
|
||||
<div class="group-section-title privateSection">
|
||||
<h2><span class="icon"><i class="mdi mdi-bullhorn mdi-24px"></i></span> <span>My group section</span></h2> <a href="/@my_group@remotedomain.net/p" class="">View all</a>
|
||||
exports[`GroupSection > renders group section with basic informations 1`] = `
|
||||
"<section class=\\"flex flex-col mb-3 border-2 border-mbz-purple\\">
|
||||
<div class=\\"flex items-stretch py-3 px-1 bg-yellow-1 text-violet-title\\">
|
||||
<div class=\\"flex flex-1 gap-1\\"><span class=\\"o-icon\\"><i class=\\"mdi mdi-bullhorn 36\\"></i></span>
|
||||
<h2 class=\\"text-2xl font-medium mt-0\\">My group section</h2>
|
||||
</div><a href=\\"/@my_group@remotedomain.net/p\\" class=\\"self-center\\">View all</a>
|
||||
</div>
|
||||
<div class="main-slot">
|
||||
<div class=\\"flex-1\\">
|
||||
<div>A list of elements</div>
|
||||
</div>
|
||||
<div class="create-slot"><a href="/@my_group@remotedomain.net/p/new" class="button is-primary">+ Create a post</a></div>
|
||||
</section>
|
||||
<div class=\\"flex justify-end p-2\\"><a href=\\"/@my_group@remotedomain.net/p/new\\" class=\\"btn-primary\\">+ Create a post</a></div>
|
||||
</section>"
|
||||
`;
|
||||
|
||||
exports[`GroupSection renders public group section 1`] = `
|
||||
<section>
|
||||
<div class="group-section-title">
|
||||
<h2><span class="icon"><i class="mdi mdi-bullhorn mdi-24px"></i></span> <span>My group section</span></h2> <a href="/@my_group@remotedomain.net/p" class="">View all</a>
|
||||
exports[`GroupSection > renders public group section 1`] = `
|
||||
"<section class=\\"flex flex-col mb-3 border-2 border-yellow-1\\">
|
||||
<div class=\\"flex items-stretch py-3 px-1 bg-yellow-1 text-violet-title\\">
|
||||
<div class=\\"flex flex-1 gap-1\\"><span class=\\"o-icon\\"><i class=\\"mdi mdi-bullhorn 36\\"></i></span>
|
||||
<h2 class=\\"text-2xl font-medium mt-0\\">My group section</h2>
|
||||
</div><a href=\\"/@my_group@remotedomain.net/p\\" class=\\"self-center\\">View all</a>
|
||||
</div>
|
||||
<div class="main-slot">
|
||||
<div class=\\"flex-1\\">
|
||||
<div>A list of elements</div>
|
||||
</div>
|
||||
<div class="create-slot"><a href="/@my_group@remotedomain.net/p/new" class="button is-primary">+ Create a post</a></div>
|
||||
</section>
|
||||
<div class=\\"flex justify-end p-2\\"><a href=\\"/@my_group@remotedomain.net/p/new\\" class=\\"btn-primary\\">+ Create a post</a></div>
|
||||
</section>"
|
||||
`;
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
import { config, createLocalVue, mount, Wrapper } from "@vue/test-utils";
|
||||
import { config, mount, VueWrapper } from "@vue/test-utils";
|
||||
import ParticipationSection from "@/components/Participation/ParticipationSection.vue";
|
||||
import Buefy from "buefy";
|
||||
import VueRouter from "vue-router";
|
||||
import { createRouter, createWebHistory, Router } from "vue-router";
|
||||
import { routes } from "@/router";
|
||||
import { CommentModeration, EventJoinOptions } from "@/types/enums";
|
||||
import {
|
||||
createMockClient,
|
||||
MockApolloClient,
|
||||
RequestHandler,
|
||||
} from "mock-apollo-client";
|
||||
import { CONFIG } from "@/graphql/config";
|
||||
import VueApollo from "@vue/apollo-option";
|
||||
import { configMock } from "../../mocks/config";
|
||||
import { InMemoryCache } from "@apollo/client/cache";
|
||||
import { defaultResolvers } from "../../common";
|
||||
import { beforeEach, describe, expect, vi, it } from "vitest";
|
||||
import Oruga from "@oruga-ui/oruga-next";
|
||||
import FloatingVue from "floating-vue";
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Buefy);
|
||||
localVue.use(VueRouter);
|
||||
const router = new VueRouter({ routes, mode: "history" });
|
||||
config.mocks.$t = (key: string): string => key;
|
||||
config.global.plugins.push(Oruga);
|
||||
config.global.plugins.push(FloatingVue);
|
||||
|
||||
let router: Router;
|
||||
|
||||
beforeEach(async () => {
|
||||
router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: routes,
|
||||
});
|
||||
|
||||
// await router.isReady();
|
||||
});
|
||||
const eventData = {
|
||||
id: "1",
|
||||
uuid: "e37910ea-fd5a-4756-7634-00971f3f4107",
|
||||
@@ -32,49 +32,31 @@ const eventData = {
|
||||
};
|
||||
|
||||
describe("ParticipationSection", () => {
|
||||
let wrapper: Wrapper<Vue>;
|
||||
let mockClient: MockApolloClient;
|
||||
let apolloProvider;
|
||||
let requestHandlers: Record<string, RequestHandler>;
|
||||
let wrapper: VueWrapper;
|
||||
|
||||
const generateWrapper = (
|
||||
handlers: Record<string, unknown> = {},
|
||||
customProps: Record<string, unknown> = {},
|
||||
baseData: Record<string, unknown> = {}
|
||||
) => {
|
||||
const cache = new InMemoryCache({ addTypename: false });
|
||||
|
||||
mockClient = createMockClient({
|
||||
cache,
|
||||
resolvers: defaultResolvers,
|
||||
});
|
||||
requestHandlers = {
|
||||
configQueryHandler: jest.fn().mockResolvedValue(configMock),
|
||||
...handlers,
|
||||
};
|
||||
mockClient.setRequestHandler(CONFIG, requestHandlers.configQueryHandler);
|
||||
|
||||
apolloProvider = new VueApollo({
|
||||
defaultClient: mockClient,
|
||||
});
|
||||
|
||||
wrapper = mount(ParticipationSection, {
|
||||
localVue,
|
||||
router,
|
||||
apolloProvider,
|
||||
stubs: {
|
||||
ParticipationButton: true,
|
||||
},
|
||||
propsData: {
|
||||
props: {
|
||||
participation: null,
|
||||
event: eventData,
|
||||
anonymousParticipation: null,
|
||||
currentActor: { id: "5" },
|
||||
identities: [],
|
||||
anonymousParticipationConfig: {
|
||||
allowed: true,
|
||||
},
|
||||
...customProps,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
...baseData,
|
||||
};
|
||||
global: {
|
||||
plugins: [router],
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -84,8 +66,6 @@ describe("ParticipationSection", () => {
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
expect(wrapper.exists()).toBe(true);
|
||||
expect(requestHandlers.configQueryHandler).toHaveBeenCalled();
|
||||
expect(wrapper.vm.$apollo.queries.config).toBeTruthy();
|
||||
|
||||
expect(wrapper.find(".event-participation").exists()).toBeTruthy();
|
||||
|
||||
@@ -101,14 +81,14 @@ describe("ParticipationSection", () => {
|
||||
});
|
||||
|
||||
it("renders the participation section with existing confimed anonymous participation", async () => {
|
||||
generateWrapper({}, { anonymousParticipation: true });
|
||||
generateWrapper({ anonymousParticipation: true });
|
||||
|
||||
expect(wrapper.find(".event-participation > small").text()).toContain(
|
||||
"You are participating in this event anonymously"
|
||||
);
|
||||
|
||||
const cancelAnonymousParticipationButton = wrapper.find(
|
||||
".event-participation > button.button.is-text"
|
||||
".event-participation > button.o-btn--text"
|
||||
);
|
||||
expect(cancelAnonymousParticipationButton.text()).toBe(
|
||||
"Cancel anonymous participation"
|
||||
@@ -127,20 +107,17 @@ describe("ParticipationSection", () => {
|
||||
});
|
||||
|
||||
it("renders the participation section with existing confimed anonymous participation but event moderation", async () => {
|
||||
generateWrapper(
|
||||
{},
|
||||
{
|
||||
anonymousParticipation: true,
|
||||
event: { ...eventData, joinOptions: EventJoinOptions.RESTRICTED },
|
||||
}
|
||||
);
|
||||
generateWrapper({
|
||||
anonymousParticipation: true,
|
||||
event: { ...eventData, joinOptions: EventJoinOptions.RESTRICTED },
|
||||
});
|
||||
|
||||
expect(wrapper.find(".event-participation > small").text()).toContain(
|
||||
"You are participating in this event anonymously"
|
||||
);
|
||||
|
||||
const cancelAnonymousParticipationButton = wrapper.find(
|
||||
".event-participation > button.button.is-text"
|
||||
".event-participation > button.o-btn--text"
|
||||
);
|
||||
expect(cancelAnonymousParticipationButton.text()).toBe(
|
||||
"Cancel anonymous participation"
|
||||
@@ -153,7 +130,7 @@ describe("ParticipationSection", () => {
|
||||
ref: "anonymous-participation-modal",
|
||||
});
|
||||
expect(modal.isVisible()).toBeTruthy();
|
||||
expect(modal.find("article.notification.is-primary").text()).toBe(
|
||||
expect(modal.find(".o-notification--primary").text()).toBe(
|
||||
"As the event organizer has chosen to manually validate participation requests, your participation will be really confirmed only once you receive an email stating it's being accepted."
|
||||
);
|
||||
|
||||
@@ -163,7 +140,7 @@ describe("ParticipationSection", () => {
|
||||
});
|
||||
|
||||
it("renders the participation section with existing unconfirmed anonymous participation", async () => {
|
||||
generateWrapper({}, { anonymousParticipation: false });
|
||||
generateWrapper({ anonymousParticipation: false });
|
||||
|
||||
expect(wrapper.find(".event-participation > small").text()).toContain(
|
||||
"You are participating in this event anonymously but didn't confirm participation"
|
||||
@@ -171,19 +148,16 @@ describe("ParticipationSection", () => {
|
||||
});
|
||||
|
||||
it("renders the participation section but the event is already passed", async () => {
|
||||
generateWrapper(
|
||||
{},
|
||||
{
|
||||
event: {
|
||||
...eventData,
|
||||
beginsOn: "2020-12-02T10:52:56Z",
|
||||
endsOn: "2020-12-03T10:52:56Z",
|
||||
},
|
||||
}
|
||||
);
|
||||
generateWrapper({
|
||||
event: {
|
||||
...eventData,
|
||||
beginsOn: "2020-12-02T10:52:56Z",
|
||||
endsOn: "2020-12-03T10:52:56Z",
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.find(".event-participation").exists()).toBeFalsy();
|
||||
expect(wrapper.find("button.button.is-primary").text()).toBe(
|
||||
expect(wrapper.find("button.o-btn--primary").text()).toBe(
|
||||
"Event already passed"
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { config, createLocalVue, mount, Wrapper } from "@vue/test-utils";
|
||||
import { config, mount, VueWrapper } from "@vue/test-utils";
|
||||
import ParticipationWithoutAccount from "@/components/Participation/ParticipationWithoutAccount.vue";
|
||||
import Buefy from "buefy";
|
||||
import VueRouter from "vue-router";
|
||||
import { routes } from "@/router";
|
||||
import {
|
||||
CommentModeration,
|
||||
@@ -13,26 +11,34 @@ import {
|
||||
MockApolloClient,
|
||||
RequestHandler,
|
||||
} from "mock-apollo-client";
|
||||
import { CONFIG } from "@/graphql/config";
|
||||
import VueApollo from "@vue/apollo-option";
|
||||
import { ANONYMOUS_ACTOR_ID } from "@/graphql/config";
|
||||
import { FETCH_EVENT_BASIC, JOIN_EVENT } from "@/graphql/event";
|
||||
import { IEvent } from "@/types/event.model";
|
||||
import { i18n } from "@/utils/i18n";
|
||||
import { configMock } from "../../mocks/config";
|
||||
import { anonymousActorIdMock } from "../../mocks/config";
|
||||
import {
|
||||
fetchEventBasicMock,
|
||||
joinEventMock,
|
||||
joinEventResponseMock,
|
||||
} from "../../mocks/event";
|
||||
import { InMemoryCache } from "@apollo/client/cache";
|
||||
import { defaultResolvers } from "../../common";
|
||||
import flushPromises from "flush-promises";
|
||||
import { vi, describe, expect, it, beforeEach, afterEach } from "vitest";
|
||||
import { DefaultApolloClient } from "@vue/apollo-composable";
|
||||
import { Router, createRouter, createWebHistory } from "vue-router";
|
||||
import Oruga from "@oruga-ui/oruga-next";
|
||||
import { cache } from "@/apollo/memory";
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Buefy);
|
||||
localVue.use(VueRouter);
|
||||
const router = new VueRouter({ routes, mode: "history" });
|
||||
config.mocks.$t = (key: string): string => key;
|
||||
config.global.plugins.push(Oruga);
|
||||
let router: Router;
|
||||
|
||||
beforeEach(async () => {
|
||||
router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: routes,
|
||||
});
|
||||
|
||||
// await router.isReady();
|
||||
});
|
||||
|
||||
const eventData = {
|
||||
id: "1",
|
||||
@@ -56,31 +62,38 @@ const eventData = {
|
||||
};
|
||||
|
||||
describe("ParticipationWithoutAccount", () => {
|
||||
let wrapper: Wrapper<Vue>;
|
||||
let mockClient: MockApolloClient;
|
||||
let apolloProvider;
|
||||
let wrapper: VueWrapper;
|
||||
let mockClient: MockApolloClient | null;
|
||||
let requestHandlers: Record<string, RequestHandler>;
|
||||
|
||||
afterEach(() => {
|
||||
wrapper?.unmount();
|
||||
cache.reset();
|
||||
mockClient = null;
|
||||
});
|
||||
|
||||
const generateWrapper = (
|
||||
handlers: Record<string, unknown> = {},
|
||||
customProps: Record<string, unknown> = {},
|
||||
baseData: Record<string, unknown> = {}
|
||||
customProps: Record<string, unknown> = {}
|
||||
) => {
|
||||
const cache = new InMemoryCache({ addTypename: false });
|
||||
|
||||
mockClient = createMockClient({
|
||||
cache,
|
||||
resolvers: defaultResolvers,
|
||||
});
|
||||
requestHandlers = {
|
||||
configQueryHandler: jest.fn().mockResolvedValue(configMock),
|
||||
fetchEventQueryHandler: jest.fn().mockResolvedValue(fetchEventBasicMock),
|
||||
joinEventMutationHandler: jest
|
||||
anonymousActorIdQueryHandler: vi
|
||||
.fn()
|
||||
.mockResolvedValue(anonymousActorIdMock),
|
||||
fetchEventQueryHandler: vi.fn().mockResolvedValue(fetchEventBasicMock),
|
||||
joinEventMutationHandler: vi
|
||||
.fn()
|
||||
.mockResolvedValue(joinEventResponseMock),
|
||||
...handlers,
|
||||
};
|
||||
mockClient.setRequestHandler(CONFIG, requestHandlers.configQueryHandler);
|
||||
mockClient.setRequestHandler(
|
||||
ANONYMOUS_ACTOR_ID,
|
||||
requestHandlers.anonymousActorIdQueryHandler
|
||||
);
|
||||
mockClient.setRequestHandler(
|
||||
FETCH_EVENT_BASIC,
|
||||
requestHandlers.fetchEventQueryHandler
|
||||
@@ -90,43 +103,33 @@ describe("ParticipationWithoutAccount", () => {
|
||||
requestHandlers.joinEventMutationHandler
|
||||
);
|
||||
|
||||
apolloProvider = new VueApollo({
|
||||
defaultClient: mockClient,
|
||||
});
|
||||
|
||||
wrapper = mount(ParticipationWithoutAccount, {
|
||||
localVue,
|
||||
router,
|
||||
i18n,
|
||||
apolloProvider,
|
||||
propsData: {
|
||||
props: {
|
||||
uuid: eventData.uuid,
|
||||
...customProps,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
...baseData,
|
||||
};
|
||||
global: {
|
||||
provide: {
|
||||
[DefaultApolloClient]: mockClient,
|
||||
},
|
||||
plugins: [router],
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
it("renders the participation without account view with minimal data", async () => {
|
||||
generateWrapper();
|
||||
await wrapper.vm.$nextTick();
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
expect(wrapper.exists()).toBe(true);
|
||||
expect(requestHandlers.configQueryHandler).toHaveBeenCalled();
|
||||
expect(wrapper.vm.$apollo.queries.config).toBeTruthy();
|
||||
expect(requestHandlers.anonymousActorIdQueryHandler).toHaveBeenCalled();
|
||||
|
||||
expect(requestHandlers.fetchEventQueryHandler).toHaveBeenCalledWith({
|
||||
uuid: eventData.uuid,
|
||||
});
|
||||
expect(wrapper.vm.$apollo.queries.event).toBeTruthy();
|
||||
await flushPromises();
|
||||
|
||||
expect(wrapper.find(".hero-body .container").isVisible()).toBeTruthy();
|
||||
expect(wrapper.find("article.message.is-info").text()).toBe(
|
||||
expect(wrapper.find(".container").isVisible()).toBeTruthy();
|
||||
expect(wrapper.find(".o-notification--info").text()).toBe(
|
||||
"Your email will only be used to confirm that you're a real person and send you eventual updates for this event. It will NOT be transmitted to other instances or to the event organizer."
|
||||
);
|
||||
|
||||
@@ -134,13 +137,13 @@ describe("ParticipationWithoutAccount", () => {
|
||||
wrapper.find("textarea").setValue("a message long enough");
|
||||
wrapper.find("form").trigger("submit");
|
||||
|
||||
await wrapper.vm.$nextTick();
|
||||
await flushPromises();
|
||||
|
||||
expect(requestHandlers.joinEventMutationHandler).toHaveBeenCalledWith({
|
||||
...joinEventMock,
|
||||
});
|
||||
|
||||
const cachedData = mockClient.cache.readQuery<{ event: IEvent }>({
|
||||
const cachedData = mockClient?.cache.readQuery<{ event: IEvent }>({
|
||||
query: FETCH_EVENT_BASIC,
|
||||
variables: {
|
||||
uuid: eventData.uuid,
|
||||
@@ -161,10 +164,10 @@ describe("ParticipationWithoutAccount", () => {
|
||||
expect(wrapper.find("h1.title").text()).toBe(
|
||||
"Request for participation confirmation sent"
|
||||
);
|
||||
// TextEncoder is not in js-dom
|
||||
expect(
|
||||
wrapper.find("article.message.is-warning .media-content").text()
|
||||
).toBe("Unable to save your participation in this browser.");
|
||||
// TextEncoder ~is~ was not in js-dom?
|
||||
// expect(wrapper.find(".o-notification--error").text()).toBe(
|
||||
// "Unable to save your participation in this browser."
|
||||
// );
|
||||
|
||||
expect(wrapper.find("span.details").text()).toBe(
|
||||
"Your participation will be validated once you click the confirmation link into the email."
|
||||
@@ -174,7 +177,7 @@ describe("ParticipationWithoutAccount", () => {
|
||||
|
||||
it("renders the warning if the event participation is restricted", async () => {
|
||||
generateWrapper({
|
||||
fetchEventQueryHandler: jest.fn().mockResolvedValue({
|
||||
fetchEventQueryHandler: vi.fn().mockResolvedValue({
|
||||
data: {
|
||||
event: {
|
||||
...fetchEventBasicMock.data.event,
|
||||
@@ -182,7 +185,7 @@ describe("ParticipationWithoutAccount", () => {
|
||||
},
|
||||
},
|
||||
}),
|
||||
joinEventMutationHandler: jest.fn().mockResolvedValue({
|
||||
joinEventMutationHandler: vi.fn().mockResolvedValue({
|
||||
data: {
|
||||
joinEvent: {
|
||||
...joinEventResponseMock.data.joinEvent,
|
||||
@@ -192,17 +195,18 @@ describe("ParticipationWithoutAccount", () => {
|
||||
}),
|
||||
});
|
||||
|
||||
await wrapper.vm.$nextTick();
|
||||
await wrapper.vm.$nextTick();
|
||||
await flushPromises();
|
||||
|
||||
expect(wrapper.vm.$data.event.joinOptions).toBe(
|
||||
EventJoinOptions.RESTRICTED
|
||||
);
|
||||
// expect(wrapper.vm.$data.event.joinOptions).toBe(
|
||||
// EventJoinOptions.RESTRICTED
|
||||
// );
|
||||
|
||||
expect(wrapper.find(".hero-body .container").text()).toContain(
|
||||
expect(wrapper.findAll("section.container form > p")[1].text()).toContain(
|
||||
"The event organizer manually approves participations. Since you've chosen to participate without an account, please explain why you want to participate to this event."
|
||||
);
|
||||
expect(wrapper.find(".hero-body .container").text()).not.toContain(
|
||||
expect(
|
||||
wrapper.findAll("section.container form > p")[1].text()
|
||||
).not.toContain(
|
||||
"If you want, you may send a message to the event organizer here."
|
||||
);
|
||||
|
||||
@@ -210,13 +214,13 @@ describe("ParticipationWithoutAccount", () => {
|
||||
wrapper.find("textarea").setValue("a message long enough");
|
||||
wrapper.find("form").trigger("submit");
|
||||
|
||||
await wrapper.vm.$nextTick();
|
||||
await flushPromises();
|
||||
|
||||
expect(requestHandlers.joinEventMutationHandler).toHaveBeenCalledWith({
|
||||
...joinEventMock,
|
||||
});
|
||||
|
||||
const cachedData = mockClient.cache.readQuery<{ event: IEvent }>({
|
||||
const cachedData = mockClient?.cache.readQuery<{ event: IEvent }>({
|
||||
query: FETCH_EVENT_BASIC,
|
||||
variables: {
|
||||
uuid: eventData.uuid,
|
||||
@@ -242,30 +246,28 @@ describe("ParticipationWithoutAccount", () => {
|
||||
|
||||
it("handles being already a participant", async () => {
|
||||
generateWrapper({
|
||||
joinEventMutationHandler: jest
|
||||
joinEventMutationHandler: vi
|
||||
.fn()
|
||||
.mockRejectedValue(
|
||||
new Error("You are already a participant of this event")
|
||||
),
|
||||
});
|
||||
await wrapper.vm.$nextTick();
|
||||
await wrapper.vm.$nextTick();
|
||||
await flushPromises();
|
||||
|
||||
wrapper.find('input[type="email"]').setValue("some@email.tld");
|
||||
wrapper.find("textarea").setValue("a message long enough");
|
||||
wrapper.find("form").trigger("submit");
|
||||
|
||||
await wrapper.vm.$nextTick();
|
||||
await flushPromises();
|
||||
|
||||
expect(requestHandlers.joinEventMutationHandler).toHaveBeenCalledWith({
|
||||
...joinEventMock,
|
||||
});
|
||||
await wrapper.vm.$nextTick();
|
||||
await wrapper.vm.$nextTick();
|
||||
await flushPromises();
|
||||
expect(wrapper.find("form").exists()).toBeTruthy();
|
||||
expect(
|
||||
wrapper.find("article.message.is-danger .media-content").text()
|
||||
).toContain("You are already a participant of this event");
|
||||
expect(wrapper.find(".o-notification--danger").text()).toContain(
|
||||
"You are already a participant of this event"
|
||||
);
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,130 +1,83 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`ParticipationWithoutAccount handles being already a participant 1`] = `
|
||||
<section class="container section hero is-fullheight">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<form>
|
||||
<p>
|
||||
This Mobilizon instance and this event organizer allows anonymous participations, but requires validation through email confirmation.
|
||||
</p>
|
||||
<transition-stub name="fade">
|
||||
<article class="message is-info">
|
||||
<!---->
|
||||
<section class="message-body">
|
||||
<div class="media">
|
||||
<!---->
|
||||
<div class="media-content">
|
||||
Your email will only be used to confirm that you're a real person and send you eventual updates for this event. It will NOT be transmitted to other instances or to the event organizer.
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!---->
|
||||
</article>
|
||||
</transition-stub>
|
||||
<transition-stub name="fade">
|
||||
<article class="message is-danger">
|
||||
<!---->
|
||||
<section class="message-body">
|
||||
<div class="media">
|
||||
<!---->
|
||||
<div class="media-content">You are already a participant of this event</div>
|
||||
</div>
|
||||
</section>
|
||||
<!---->
|
||||
</article>
|
||||
</transition-stub>
|
||||
<div class="field"><label class="label">Email address</label>
|
||||
<div class="control is-clearfix"><input type="email" autocomplete="on" placeholder="Your email" required="required" class="input">
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
exports[`ParticipationWithoutAccount > handles being already a participant 1`] = `
|
||||
"<section class=\\"container mx-auto\\">
|
||||
<div class=\\"\\">
|
||||
<form>
|
||||
<p>This Mobilizon instance and this event organizer allows anonymous participations, but requires validation through email confirmation.</p>
|
||||
<transition-stub>
|
||||
<article class=\\"o-notification o-notification--info\\">
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<div class=\\"o-notification__wrapper\\">
|
||||
<!--v-if-->
|
||||
<div class=\\"o-notification__content\\">Your email will only be used to confirm that you're a real person and send you eventual updates for this event. It will NOT be transmitted to other instances or to the event organizer.</div>
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
<p>
|
||||
If you want, you may send a message to the event organizer here.
|
||||
</p>
|
||||
<div class="field"><label class="label">Message</label>
|
||||
<div class="control is-clearfix"><textarea minlength="10" class="textarea"></textarea>
|
||||
<!---->
|
||||
<!---->
|
||||
<!---->
|
||||
</article>
|
||||
</transition-stub>
|
||||
<transition-stub>
|
||||
<article class=\\"o-notification o-notification--danger\\">
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<div class=\\"o-notification__wrapper\\">
|
||||
<!--v-if-->
|
||||
<div class=\\"o-notification__content\\">You are already a participant of this event</div>
|
||||
</div>
|
||||
<!---->
|
||||
</article>
|
||||
</transition-stub>
|
||||
<div class=\\"o-field o-field--filled\\"><label for=\\"anonymousParticipationEmail\\" class=\\"o-field__label\\">Email address</label>
|
||||
<div class=\\"o-ctrl-input\\"><input id=\\"anonymousParticipationEmail\\" placeholder=\\"Your email\\" required=\\"\\" class=\\"o-input\\" type=\\"email\\" autocomplete=\\"off\\">
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
</div>
|
||||
<div class="field">
|
||||
<!----><label class="b-checkbox checkbox"><input type="checkbox" autocomplete="on" true-value="true" value="false"><span class="check"></span><span class="control-label"><b>Remember my participation in this browser</b> <p>
|
||||
Will allow to display and manage your participation status on the event page when using this device. Uncheck if you're using a public device.
|
||||
</p></span></label>
|
||||
<!---->
|
||||
</div> <button type="submit" class="button is-primary">
|
||||
<!----><span>Send email</span>
|
||||
<!---->
|
||||
</button>
|
||||
<div class="has-text-centered"><a class="button is-text">
|
||||
<!----><span>Back to previous page</span>
|
||||
<!---->
|
||||
</a></div>
|
||||
</form>
|
||||
</div>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
<p>If you want, you may send a message to the event organizer here.</p>
|
||||
<div class=\\"o-field o-field--filled\\"><label for=\\"anonymousParticipationMessage\\" class=\\"o-field__label\\">Message</label>
|
||||
<div class=\\"o-ctrl-input\\"><textarea id=\\"anonymousParticipationMessage\\" minlength=\\"10\\" class=\\"o-input o-input__textarea\\"></textarea>
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
</div>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
<div class=\\"o-field\\">
|
||||
<!--v-if--><label class=\\"o-chk o-chk--checked\\"><input type=\\"checkbox\\" class=\\"o-chk__check o-chk__check--checked\\" true-value=\\"true\\" false-value=\\"false\\" value=\\"false\\"><span class=\\"o-chk__label\\"><b>Remember my participation in this browser</b><p>Will allow to display and manage your participation status on the event page when using this device. Uncheck if you're using a public device.</p></span></label>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
<div class=\\"flex gap-2 my-2\\"><button type=\\"submit\\" class=\\"o-btn o-btn--primary o-btn--disabled\\" disabled=\\"\\"><span class=\\"o-btn__wrapper\\"><!--v-if--><span class=\\"o-btn__label\\">Send email</span>
|
||||
<!--v-if--></span>
|
||||
</button><button type=\\"button\\" class=\\"o-btn o-btn--text\\"><span class=\\"o-btn__wrapper\\"><!--v-if--><span class=\\"o-btn__label\\">Back to previous page</span>
|
||||
<!--v-if--></span>
|
||||
</button></div>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</section>"
|
||||
`;
|
||||
|
||||
exports[`ParticipationWithoutAccount renders the participation without account view with minimal data 1`] = `
|
||||
<section class="container section hero is-fullheight">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<div>
|
||||
<h1 class="title">
|
||||
Request for participation confirmation sent
|
||||
</h1>
|
||||
<p class="content"><span>Check your inbox (and your junk mail folder).</span> <span class="details">Your participation will be validated once you click the confirmation link into the email.</span></p>
|
||||
<transition-stub name="fade">
|
||||
<article class="message is-warning">
|
||||
<!---->
|
||||
<section class="message-body">
|
||||
<div class="media">
|
||||
<!---->
|
||||
<div class="media-content">Unable to save your participation in this browser.</div>
|
||||
</div>
|
||||
</section>
|
||||
<!---->
|
||||
</article>
|
||||
</transition-stub>
|
||||
<p class="content"><span>You may now close this window, or <a href="/events/f37910ea-fd5a-4756-9679-00971f3f4106" class="">return to the event's page</a>.</span></p>
|
||||
</div>
|
||||
exports[`ParticipationWithoutAccount > renders the participation without account view with minimal data 1`] = `
|
||||
"<section class=\\"container mx-auto\\">
|
||||
<div class=\\"\\">
|
||||
<div>
|
||||
<h1 class=\\"title\\">Request for participation confirmation sent</h1>
|
||||
<p class=\\"prose dark:prose-invert\\"><span>Check your inbox (and your junk mail folder).</span><span class=\\"details\\">Your participation will be validated once you click the confirmation link into the email.</span></p>
|
||||
<!--v-if-->
|
||||
<p class=\\"prose dark:prose-invert\\">You may now close this window, or <a href=\\"/events/f37910ea-fd5a-4756-9679-00971f3f4106\\" class=\\"\\">return to the event's page</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>"
|
||||
`;
|
||||
|
||||
exports[`ParticipationWithoutAccount renders the warning if the event participation is restricted 1`] = `
|
||||
<section class="container section hero is-fullheight">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<div>
|
||||
<h1 class="title">
|
||||
Request for participation confirmation sent
|
||||
</h1>
|
||||
<p class="content"><span>Check your inbox (and your junk mail folder).</span> <span class="details">
|
||||
Your participation will be validated once you click the confirmation link into the email, and after the organizer manually validates your participation. </span></p>
|
||||
<transition-stub name="fade">
|
||||
<article class="message is-warning">
|
||||
<!---->
|
||||
<section class="message-body">
|
||||
<div class="media">
|
||||
<!---->
|
||||
<div class="media-content">Unable to save your participation in this browser.</div>
|
||||
</div>
|
||||
</section>
|
||||
<!---->
|
||||
</article>
|
||||
</transition-stub>
|
||||
<p class="content"><span>You may now close this window, or <a href="/events/f37910ea-fd5a-4756-9679-00971f3f4106" class="">return to the event's page</a>.</span></p>
|
||||
</div>
|
||||
exports[`ParticipationWithoutAccount > renders the warning if the event participation is restricted 1`] = `
|
||||
"<section class=\\"container mx-auto\\">
|
||||
<div class=\\"\\">
|
||||
<div>
|
||||
<h1 class=\\"title\\">Request for participation confirmation sent</h1>
|
||||
<p class=\\"prose dark:prose-invert\\"><span>Check your inbox (and your junk mail folder).</span><span class=\\"details\\">Your participation will be validated once you click the confirmation link into the email, and after the organizer manually validates your participation.</span></p>
|
||||
<!--v-if-->
|
||||
<p class=\\"prose dark:prose-invert\\">You may now close this window, or <a href=\\"/events/f37910ea-fd5a-4756-9679-00971f3f4106\\" class=\\"\\">return to the event's page</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>"
|
||||
`;
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { config, createLocalVue, mount } from "@vue/test-utils";
|
||||
import { config, mount } from "@vue/test-utils";
|
||||
import PostListItem from "@/components/Post/PostListItem.vue";
|
||||
import Buefy from "buefy";
|
||||
import VueRouter from "vue-router";
|
||||
import { routes } from "@/router";
|
||||
import { vi, beforeEach, describe, it, expect } from "vitest";
|
||||
import { enUS } from "date-fns/locale";
|
||||
import { formatDateTimeString } from "@/filters/datetime";
|
||||
import { i18n } from "@/utils/i18n";
|
||||
import { routes } from "@/router";
|
||||
import { createRouter, createWebHistory, Router } from "vue-router";
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Buefy);
|
||||
localVue.use(VueRouter);
|
||||
localVue.use((vue) => {
|
||||
vue.prototype.$dateFnsLocale = enUS;
|
||||
let router: Router;
|
||||
|
||||
beforeEach(async () => {
|
||||
router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: routes,
|
||||
});
|
||||
|
||||
// await router.isReady();
|
||||
});
|
||||
const router = new VueRouter({ routes, mode: "history" });
|
||||
config.mocks.$t = (key: string): string => key;
|
||||
|
||||
const postData = {
|
||||
id: "1",
|
||||
@@ -31,15 +31,15 @@ const generateWrapper = (
|
||||
customProps: Record<string, unknown> = {}
|
||||
) => {
|
||||
return mount(PostListItem, {
|
||||
localVue,
|
||||
router,
|
||||
i18n,
|
||||
propsData: {
|
||||
props: {
|
||||
post: { ...postData, ...customPostData },
|
||||
...customProps,
|
||||
},
|
||||
filters: {
|
||||
formatDateTimeString,
|
||||
global: {
|
||||
provide: {
|
||||
dateFnsLocale: enUS,
|
||||
},
|
||||
plugins: [router],
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -50,15 +50,15 @@ describe("PostListItem", () => {
|
||||
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
|
||||
expect(
|
||||
wrapper.find("a.post-minimalist-card-wrapper").attributes("href")
|
||||
).toBe(`/p/${postData.slug}`);
|
||||
expect(wrapper.find("a.block.bg-white").attributes("href")).toBe(
|
||||
`/p/${postData.slug}`
|
||||
);
|
||||
|
||||
expect(wrapper.find(".post-minimalist-title").text()).toBe(postData.title);
|
||||
expect(wrapper.find("h3").text()).toBe(postData.title);
|
||||
|
||||
expect(wrapper.find(".post-publication-date").text()).toBe("Dec 2, 2020");
|
||||
expect(wrapper.find("p.flex.gap-2").text()).toBe("Dec 2, 2020");
|
||||
|
||||
expect(wrapper.find(".post-publisher").exists()).toBeFalsy();
|
||||
expect(wrapper.find("p.flex.gap-1").exists()).toBeFalsy();
|
||||
});
|
||||
|
||||
it("renders post list item with tags", () => {
|
||||
@@ -68,9 +68,11 @@ describe("PostListItem", () => {
|
||||
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
|
||||
expect(wrapper.find(".tags").text()).toContain("A tag");
|
||||
expect(wrapper.find("div.flex.flex-wrap.gap-y-0.gap-x-2").text()).toContain(
|
||||
"A tag"
|
||||
);
|
||||
|
||||
expect(wrapper.find(".post-publisher").exists()).toBeFalsy();
|
||||
expect(wrapper.find("p.flex.gap-1").exists()).toBeFalsy();
|
||||
});
|
||||
|
||||
it("renders post list item with publisher name", () => {
|
||||
@@ -81,7 +83,7 @@ describe("PostListItem", () => {
|
||||
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
|
||||
expect(wrapper.find(".post-publisher").exists()).toBeTruthy();
|
||||
expect(wrapper.find(".post-publisher").text()).toContain("An author");
|
||||
expect(wrapper.find("p.flex.gap-1").exists()).toBeTruthy();
|
||||
expect(wrapper.find("p.flex.gap-1").text()).toContain("An author");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,45 +1,37 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`PostListItem renders post list item with basic informations 1`] = `
|
||||
<a href="/p/my-blog-post-some-uuid" class="post-minimalist-card-wrapper" dir="auto">
|
||||
<!---->
|
||||
<div class="title-info-wrapper has-text-grey-dark px-1">
|
||||
<h3 lang="en" class="post-minimalist-title">
|
||||
My Blog Post
|
||||
</h3>
|
||||
<p class="post-publication-date"><span class="icon"><i class="mdi mdi-clock mdi-24px"></i></span> <span dir="auto" class="has-text-grey-dark">Dec 2, 2020</span></p>
|
||||
<!---->
|
||||
<!---->
|
||||
exports[`PostListItem > renders post list item with basic informations 1`] = `
|
||||
"<a href=\\"/p/my-blog-post-some-uuid\\" class=\\"block md:flex bg-white dark:bg-violet-2 dark:text-white dark:hover:text-white rounded-lg shadow-md\\" dir=\\"auto\\" data-v-3b2c1ec0=\\"\\">
|
||||
<!--v-if-->
|
||||
<div class=\\"flex flex-col gap-1 bg-inherit p-2 rounded-lg flex-1\\" data-v-3b2c1ec0=\\"\\">
|
||||
<h3 class=\\"text-xl color-violet-3 line-clamp-3 mb-2 font-bold\\" lang=\\"en\\" data-v-3b2c1ec0=\\"\\">My Blog Post</h3>
|
||||
<p class=\\"flex gap-2\\" data-v-3b2c1ec0=\\"\\"><span aria-hidden=\\"true\\" class=\\"material-design-icon clock-icon\\" role=\\"img\\" data-v-3b2c1ec0=\\"\\"><svg fill=\\"currentColor\\" class=\\"material-design-icon__svg\\" width=\\"24\\" height=\\"24\\" viewBox=\\"0 0 24 24\\"><path d=\\"M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M16.2,16.2L11,13V7H12.5V12.2L17,14.9L16.2,16.2Z\\"><!--v-if--></path></svg></span><span dir=\\"auto\\" class=\\"\\" data-v-3b2c1ec0=\\"\\">Dec 2, 2020</span></p>
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</a>
|
||||
</a>"
|
||||
`;
|
||||
|
||||
exports[`PostListItem renders post list item with publisher name 1`] = `
|
||||
<a href="/p/my-blog-post-some-uuid" class="post-minimalist-card-wrapper" dir="auto">
|
||||
<!---->
|
||||
<div class="title-info-wrapper has-text-grey-dark px-1">
|
||||
<h3 lang="en" class="post-minimalist-title">
|
||||
My Blog Post
|
||||
</h3>
|
||||
<p class="post-publication-date"><span class="icon"><i class="mdi mdi-clock mdi-24px"></i></span> <span dir="auto" class="has-text-grey-dark">Dec 2, 2020</span></p>
|
||||
<!---->
|
||||
<p class="post-publisher has-text-grey-dark"><span class="icon"><i class="mdi mdi-account-edit mdi-24px"></i></span> <span>Published by <b class="has-text-weight-medium">An author</b></span></p>
|
||||
exports[`PostListItem > renders post list item with publisher name 1`] = `
|
||||
"<a href=\\"/p/my-blog-post-some-uuid\\" class=\\"block md:flex bg-white dark:bg-violet-2 dark:text-white dark:hover:text-white rounded-lg shadow-md\\" dir=\\"auto\\" data-v-3b2c1ec0=\\"\\">
|
||||
<!--v-if-->
|
||||
<div class=\\"flex flex-col gap-1 bg-inherit p-2 rounded-lg flex-1\\" data-v-3b2c1ec0=\\"\\">
|
||||
<h3 class=\\"text-xl color-violet-3 line-clamp-3 mb-2 font-bold\\" lang=\\"en\\" data-v-3b2c1ec0=\\"\\">My Blog Post</h3>
|
||||
<p class=\\"flex gap-2\\" data-v-3b2c1ec0=\\"\\"><span aria-hidden=\\"true\\" class=\\"material-design-icon clock-icon\\" role=\\"img\\" data-v-3b2c1ec0=\\"\\"><svg fill=\\"currentColor\\" class=\\"material-design-icon__svg\\" width=\\"24\\" height=\\"24\\" viewBox=\\"0 0 24 24\\"><path d=\\"M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M16.2,16.2L11,13V7H12.5V12.2L17,14.9L16.2,16.2Z\\"><!--v-if--></path></svg></span><span dir=\\"auto\\" class=\\"\\" data-v-3b2c1ec0=\\"\\">Dec 2, 2020</span></p>
|
||||
<!--v-if-->
|
||||
<p class=\\"flex gap-1\\" data-v-3b2c1ec0=\\"\\"><span aria-hidden=\\"true\\" class=\\"material-design-icon account-edit-icon\\" role=\\"img\\" data-v-3b2c1ec0=\\"\\"><svg fill=\\"currentColor\\" class=\\"material-design-icon__svg\\" width=\\"24\\" height=\\"24\\" viewBox=\\"0 0 24 24\\"><path d=\\"M21.7,13.35L20.7,14.35L18.65,12.3L19.65,11.3C19.86,11.09 20.21,11.09 20.42,11.3L21.7,12.58C21.91,12.79 21.91,13.14 21.7,13.35M12,18.94L18.06,12.88L20.11,14.93L14.06,21H12V18.94M12,14C7.58,14 4,15.79 4,18V20H10V18.11L14,14.11C13.34,14.03 12.67,14 12,14M12,4A4,4 0 0,0 8,8A4,4 0 0,0 12,12A4,4 0 0,0 16,8A4,4 0 0,0 12,4Z\\"><!--v-if--></path></svg></span>Published by <b class=\\"\\" data-v-3b2c1ec0=\\"\\">An author</b></p>
|
||||
</div>
|
||||
</a>
|
||||
</a>"
|
||||
`;
|
||||
|
||||
exports[`PostListItem renders post list item with tags 1`] = `
|
||||
<a href="/p/my-blog-post-some-uuid" class="post-minimalist-card-wrapper" dir="auto">
|
||||
<!---->
|
||||
<div class="title-info-wrapper has-text-grey-dark px-1">
|
||||
<h3 lang="en" class="post-minimalist-title">
|
||||
My Blog Post
|
||||
</h3>
|
||||
<p class="post-publication-date"><span class="icon"><i class="mdi mdi-clock mdi-24px"></i></span> <span dir="auto" class="has-text-grey-dark">Dec 2, 2020</span></p>
|
||||
<div class="tags" style="display: inline;"><span class="icon"><i class="mdi mdi-tag mdi-24px"></i></span> <span class="tag"><!----><span class="">A tag</span>
|
||||
<!----></span>
|
||||
</div>
|
||||
<!---->
|
||||
exports[`PostListItem > renders post list item with tags 1`] = `
|
||||
"<a href=\\"/p/my-blog-post-some-uuid\\" class=\\"block md:flex bg-white dark:bg-violet-2 dark:text-white dark:hover:text-white rounded-lg shadow-md\\" dir=\\"auto\\" data-v-3b2c1ec0=\\"\\">
|
||||
<!--v-if-->
|
||||
<div class=\\"flex flex-col gap-1 bg-inherit p-2 rounded-lg flex-1\\" data-v-3b2c1ec0=\\"\\">
|
||||
<h3 class=\\"text-xl color-violet-3 line-clamp-3 mb-2 font-bold\\" lang=\\"en\\" data-v-3b2c1ec0=\\"\\">My Blog Post</h3>
|
||||
<p class=\\"flex gap-2\\" data-v-3b2c1ec0=\\"\\"><span aria-hidden=\\"true\\" class=\\"material-design-icon clock-icon\\" role=\\"img\\" data-v-3b2c1ec0=\\"\\"><svg fill=\\"currentColor\\" class=\\"material-design-icon__svg\\" width=\\"24\\" height=\\"24\\" viewBox=\\"0 0 24 24\\"><path d=\\"M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M16.2,16.2L11,13V7H12.5V12.2L17,14.9L16.2,16.2Z\\"><!--v-if--></path></svg></span><span dir=\\"auto\\" class=\\"\\" data-v-3b2c1ec0=\\"\\">Dec 2, 2020</span></p>
|
||||
<div class=\\"flex flex-wrap gap-y-0 gap-x-2\\" data-v-3b2c1ec0=\\"\\"><span aria-hidden=\\"true\\" class=\\"material-design-icon tag-icon\\" role=\\"img\\" data-v-3b2c1ec0=\\"\\"><svg fill=\\"currentColor\\" class=\\"material-design-icon__svg\\" width=\\"24\\" height=\\"24\\" viewBox=\\"0 0 24 24\\"><path d=\\"M5.5,7A1.5,1.5 0 0,1 4,5.5A1.5,1.5 0 0,1 5.5,4A1.5,1.5 0 0,1 7,5.5A1.5,1.5 0 0,1 5.5,7M21.41,11.58L12.41,2.58C12.05,2.22 11.55,2 11,2H4C2.89,2 2,2.89 2,4V11C2,11.55 2.22,12.05 2.59,12.41L11.58,21.41C11.95,21.77 12.45,22 13,22C13.55,22 14.05,21.77 14.41,21.41L21.41,14.41C21.78,14.05 22,13.55 22,13C22,12.44 21.77,11.94 21.41,11.58Z\\"><!--v-if--></path></svg></span><span class=\\"rounded-md my-1 truncate text-sm text-violet-title capitalize px-2 py-1 bg-purple-3 dark:text-violet-3\\" data-v-bb7ceecc=\\"\\" data-v-3b2c1ec0=\\"\\">A tag</span></div>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</a>
|
||||
</a>"
|
||||
`;
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
import { config, createLocalVue, mount } from "@vue/test-utils";
|
||||
import { config, 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;
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { createI18n } from "vue-i18n";
|
||||
import en from "@/i18n/en_US.json";
|
||||
|
||||
const reportData = {
|
||||
id: "1",
|
||||
content: "My content",
|
||||
insertedAt: "2020-12-02T09:01:20.873Z",
|
||||
reporter: {
|
||||
preferredUsername: "author",
|
||||
preferredUsername: "John Snow",
|
||||
domain: null,
|
||||
name: "Reporter of Things",
|
||||
type: ActorType.PERSON,
|
||||
@@ -26,7 +24,6 @@ const reportData = {
|
||||
|
||||
const generateWrapper = (customReportData: Record<string, unknown> = {}) => {
|
||||
return mount(ReportCard, {
|
||||
localVue,
|
||||
propsData: {
|
||||
report: { ...reportData, ...customReportData },
|
||||
},
|
||||
@@ -37,16 +34,16 @@ describe("ReportCard", () => {
|
||||
it("renders report card with basic informations", () => {
|
||||
const wrapper = generateWrapper();
|
||||
|
||||
expect(wrapper.find(".media-content .title").text()).toBe(
|
||||
expect(wrapper.find(".flex.gap-1 div p:first-child").text()).toBe(
|
||||
reportData.reported.name
|
||||
);
|
||||
|
||||
expect(wrapper.find(".media-content .subtitle").text()).toBe(
|
||||
expect(wrapper.find(".flex.gap-1 div p:nth-child(2)").text()).toBe(
|
||||
`@${reportData.reported.preferredUsername}`
|
||||
);
|
||||
|
||||
expect(wrapper.find(".is-one-quarter-desktop span").text()).toBe(
|
||||
`Reported by {reporter}`
|
||||
expect(wrapper.find(".reported_by div:first-child").text()).toBe(
|
||||
`Reported by John Snow`
|
||||
);
|
||||
});
|
||||
|
||||
@@ -55,8 +52,8 @@ describe("ReportCard", () => {
|
||||
reporter: { domain: "somewhere.else", type: ActorType.APPLICATION },
|
||||
});
|
||||
|
||||
expect(wrapper.find(".is-one-quarter-desktop span").text()).toBe(
|
||||
"Reported by someone on {domain}"
|
||||
expect(wrapper.find(".reported_by div:first-child").text()).toBe(
|
||||
"Reported by someone on somewhere.else"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import { config, createLocalVue, mount } from "@vue/test-utils";
|
||||
import { config, mount } from "@vue/test-utils";
|
||||
import ReportModal from "@/components/Report/ReportModal.vue";
|
||||
import Buefy from "buefy";
|
||||
import { vi, beforeEach, describe, it, expect } from "vitest";
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Buefy);
|
||||
config.mocks.$t = (key: string): string => key;
|
||||
import Oruga from "@oruga-ui/oruga-next";
|
||||
|
||||
config.global.plugins.push(Oruga);
|
||||
|
||||
const propsData = {
|
||||
onConfirm: jest.fn(),
|
||||
onConfirm: vi.fn(),
|
||||
};
|
||||
|
||||
const generateWrapper = (customPropsData: Record<string, unknown> = {}) => {
|
||||
return mount(ReportModal, {
|
||||
localVue,
|
||||
propsData: {
|
||||
props: {
|
||||
...propsData,
|
||||
...customPropsData,
|
||||
},
|
||||
@@ -21,24 +20,22 @@ const generateWrapper = (customPropsData: Record<string, unknown> = {}) => {
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
vi.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("header").exists()).toBe(false);
|
||||
|
||||
expect(wrapper.find(".media-content").text()).not.toContain(
|
||||
expect(wrapper.find("section").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");
|
||||
expect(wrapper.find("footer button:first-child").text()).toBe("Cancel");
|
||||
|
||||
const submit = wrapper.find("footer.modal-card-foot button.is-primary");
|
||||
const submit = wrapper.find("footer button.o-btn--primary");
|
||||
|
||||
expect(submit.text()).toBe("Send the report");
|
||||
|
||||
@@ -47,7 +44,7 @@ describe("ReportModal", () => {
|
||||
|
||||
submit.trigger("click");
|
||||
|
||||
await localVue.nextTick();
|
||||
await wrapper.vm.$nextTick();
|
||||
expect(wrapper.emitted().close).toBeTruthy();
|
||||
|
||||
expect(wrapper.vm.$props.onConfirm).toHaveBeenCalledTimes(1);
|
||||
@@ -55,6 +52,7 @@ describe("ReportModal", () => {
|
||||
"some comment with my report",
|
||||
false
|
||||
);
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders report modal and shows an inline comment if it's provided", async () => {
|
||||
@@ -78,13 +76,13 @@ describe("ReportModal", () => {
|
||||
it("renders report modal with with a remote content", async () => {
|
||||
const wrapper = generateWrapper({ outsideDomain: "somewhere.else" });
|
||||
|
||||
expect(wrapper.find(".media-content").text()).toContain(
|
||||
expect(wrapper.find(".control p").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");
|
||||
const submit = wrapper.find("footer button.o-btn--primary");
|
||||
submit.trigger("click");
|
||||
await localVue.nextTick();
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
expect(wrapper.vm.$props.onConfirm).toHaveBeenCalledTimes(1);
|
||||
expect(wrapper.vm.$props.onConfirm).toHaveBeenCalledWith("", false);
|
||||
@@ -93,16 +91,16 @@ describe("ReportModal", () => {
|
||||
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(
|
||||
expect(wrapper.find(".control p").text()).toContain(
|
||||
"The content came from another server. Transfer an anonymous copy of the report?"
|
||||
);
|
||||
|
||||
const switchButton = wrapper.find('input[type="checkbox"]');
|
||||
switchButton.setChecked();
|
||||
switchButton.setValue(true);
|
||||
|
||||
const submit = wrapper.find("footer.modal-card-foot button.is-primary");
|
||||
const submit = wrapper.find("footer button.o-btn--primary");
|
||||
submit.trigger("click");
|
||||
await localVue.nextTick();
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
expect(wrapper.vm.$props.onConfirm).toHaveBeenCalledTimes(1);
|
||||
expect(wrapper.vm.$props.onConfirm).toHaveBeenCalledWith("", true);
|
||||
@@ -115,16 +113,10 @@ describe("ReportModal", () => {
|
||||
confirmText: "report!",
|
||||
});
|
||||
|
||||
expect(wrapper.find(".modal-card-head .modal-card-title").text()).toBe(
|
||||
"want to report something?"
|
||||
);
|
||||
expect(wrapper.find("header h2").text()).toBe("want to report something?");
|
||||
|
||||
expect(
|
||||
wrapper.find("footer.modal-card-foot button:first-child").text()
|
||||
).toBe("nah");
|
||||
expect(wrapper.find("footer button:first-child").text()).toBe("nah");
|
||||
|
||||
expect(
|
||||
wrapper.find("footer.modal-card-foot button.is-primary").text()
|
||||
).toBe("report!");
|
||||
expect(wrapper.find("footer button.o-btn--primary").text()).toBe("report!");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`ReportModal > renders report modal with basic informations and submits it 1`] = `
|
||||
"<div class=\\"p-2\\" data-v-8c6db6e4=\\"\\">
|
||||
<!--v-if-->
|
||||
<section data-v-8c6db6e4=\\"\\">
|
||||
<div class=\\"flex gap-1 flex-row mb-3\\" data-v-8c6db6e4=\\"\\"><span class=\\"o-icon o-icon--warning hidden md:block flex-1\\" data-v-8c6db6e4=\\"\\"><i class=\\"mdi mdi-alert 48\\"></i></span>
|
||||
<p data-v-8c6db6e4=\\"\\">The report will be sent to the moderators of your instance. You can explain why you report this content below.</p>
|
||||
</div>
|
||||
<div class=\\"\\" data-v-8c6db6e4=\\"\\">
|
||||
<!--v-if-->
|
||||
<div class=\\"o-field o-field--filled\\" data-v-8c6db6e4=\\"\\"><label for=\\"additonal-comments\\" class=\\"o-field__label\\">Additional comments</label>
|
||||
<div class=\\"o-ctrl-input\\" data-v-8c6db6e4=\\"\\"><textarea id=\\"additonal-comments\\" class=\\"o-input o-input__textarea\\"></textarea>
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
</div>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</section>
|
||||
<footer class=\\"flex gap-2 py-3\\" data-v-8c6db6e4=\\"\\"><button type=\\"button\\" class=\\"o-btn\\" data-v-8c6db6e4=\\"\\"><span class=\\"o-btn__wrapper\\"><!--v-if--><span class=\\"o-btn__label\\">Cancel</span>
|
||||
<!--v-if--></span>
|
||||
</button><button type=\\"button\\" class=\\"o-btn o-btn--primary\\" data-v-8c6db6e4=\\"\\"><span class=\\"o-btn__wrapper\\"><!--v-if--><span class=\\"o-btn__label\\">Send the report</span>
|
||||
<!--v-if--></span>
|
||||
</button></footer>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1,17 +1,23 @@
|
||||
import { config, createLocalVue, mount } from "@vue/test-utils";
|
||||
const useRouterMock = vi.fn(() => ({
|
||||
push: () => {},
|
||||
}));
|
||||
|
||||
import { config, mount } from "@vue/test-utils";
|
||||
import PasswordReset from "@/views/User/PasswordReset.vue";
|
||||
import Buefy from "buefy";
|
||||
import { createMockClient, RequestHandler } from "mock-apollo-client";
|
||||
import { RESET_PASSWORD } from "@/graphql/auth";
|
||||
import VueApollo from "@vue/apollo-option";
|
||||
import { resetPasswordResponseMock } from "../../mocks/auth";
|
||||
import RouteName from "@/router/name";
|
||||
import flushPromises from "flush-promises";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { DefaultApolloClient } from "@vue/apollo-composable";
|
||||
import Oruga from "@oruga-ui/oruga-next";
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Buefy);
|
||||
config.mocks.$t = (key: string): string => key;
|
||||
const $router = { push: jest.fn() };
|
||||
config.global.plugins.push(Oruga);
|
||||
|
||||
vi.mock("vue-router/dist/vue-router.mjs", () => ({
|
||||
useRouter: useRouterMock,
|
||||
}));
|
||||
|
||||
let requestHandlers: Record<string, RequestHandler>;
|
||||
|
||||
@@ -22,7 +28,7 @@ const generateWrapper = (
|
||||
const mockClient = createMockClient();
|
||||
|
||||
requestHandlers = {
|
||||
resetPasswordMutationHandler: jest
|
||||
resetPasswordMutationHandler: vi
|
||||
.fn()
|
||||
.mockResolvedValue(resetPasswordResponseMock),
|
||||
...customRequestHandlers,
|
||||
@@ -33,21 +39,19 @@ const generateWrapper = (
|
||||
requestHandlers.resetPasswordMutationHandler
|
||||
);
|
||||
|
||||
const apolloProvider = new VueApollo({
|
||||
defaultClient: mockClient,
|
||||
});
|
||||
|
||||
return mount(PasswordReset, {
|
||||
localVue,
|
||||
mocks: {
|
||||
$route: { query: {} },
|
||||
$router,
|
||||
...customMocks,
|
||||
},
|
||||
apolloProvider,
|
||||
propsData: {
|
||||
props: {
|
||||
token: "some-token",
|
||||
},
|
||||
global: {
|
||||
stubs: ["router-link", "router-view"],
|
||||
mocks: {
|
||||
...customMocks,
|
||||
},
|
||||
provide: {
|
||||
[DefaultApolloClient]: mockClient,
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -60,12 +64,14 @@ describe("Reset page", () => {
|
||||
|
||||
it("shows error if token is invalid", async () => {
|
||||
const wrapper = generateWrapper({
|
||||
resetPasswordMutationHandler: jest.fn().mockResolvedValue({
|
||||
resetPasswordMutationHandler: vi.fn().mockResolvedValue({
|
||||
errors: [{ message: "The token you provided is invalid." }],
|
||||
}),
|
||||
});
|
||||
|
||||
wrapper.findAll('input[type="password"').setValue("my password");
|
||||
wrapper
|
||||
.findAll('input[type="password"')
|
||||
.forEach((inputField) => inputField.setValue("my password"));
|
||||
wrapper.find("form").trigger("submit");
|
||||
|
||||
await wrapper.vm.$nextTick();
|
||||
@@ -78,27 +84,30 @@ describe("Reset page", () => {
|
||||
|
||||
await flushPromises();
|
||||
|
||||
expect(wrapper.find("article.message.is-danger").text()).toContain(
|
||||
expect(wrapper.find(".o-notification--danger").text()).toContain(
|
||||
"The token you provided is invalid"
|
||||
);
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("redirects to homepage if token is valid", async () => {
|
||||
const push = vi.fn(); // needs to write this code before render()
|
||||
useRouterMock.mockImplementationOnce(() => ({
|
||||
push,
|
||||
}));
|
||||
const wrapper = generateWrapper();
|
||||
|
||||
wrapper.findAll('input[type="password"').setValue("my password");
|
||||
wrapper.find("form").trigger("submit");
|
||||
|
||||
await wrapper.vm.$nextTick();
|
||||
wrapper
|
||||
.findAll('input[type="password"')
|
||||
.forEach((inputField) => inputField.setValue("my password"));
|
||||
await wrapper.find("form").trigger("submit");
|
||||
|
||||
expect(requestHandlers.resetPasswordMutationHandler).toBeCalledTimes(1);
|
||||
expect(requestHandlers.resetPasswordMutationHandler).toBeCalledWith({
|
||||
password: "my password",
|
||||
token: "some-token",
|
||||
});
|
||||
expect(jest.isMockFunction(wrapper.vm.$router.push)).toBe(true);
|
||||
await flushPromises();
|
||||
expect($router.push).toHaveBeenCalledWith({ name: RouteName.HOME });
|
||||
expect(push).toHaveBeenCalledWith({ name: RouteName.HOME });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,75 +1,55 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`Reset page renders correctly 1`] = `
|
||||
<section class="section container">
|
||||
<div class="columns is-mobile is-centered">
|
||||
<div class="column is-half-desktop">
|
||||
<h1 class="title">
|
||||
Password reset
|
||||
</h1>
|
||||
<form>
|
||||
<div class="field"><label class="label">Password</label>
|
||||
<div class="control has-icons-right is-clearfix"><input type="password" autocomplete="on" aria-required="true" required="required" minlength="6" class="input">
|
||||
<!----><span class="icon is-right has-text-primary is-clickable"><i class="mdi mdi-eye mdi-24px"></i></span>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
<div class="field"><label class="label">Password (confirmation)</label>
|
||||
<div class="control has-icons-right is-clearfix"><input type="password" autocomplete="on" aria-required="true" required="required" minlength="6" class="input">
|
||||
<!----><span class="icon is-right has-text-primary is-clickable"><i class="mdi mdi-eye mdi-24px"></i></span>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
</div> <button class="button is-primary">
|
||||
Reset my password
|
||||
</button>
|
||||
</form>
|
||||
exports[`Reset page > renders correctly 1`] = `
|
||||
"<section class=\\"container mx-auto\\">
|
||||
<h1 class=\\"\\">Password reset</h1>
|
||||
<form>
|
||||
<div class=\\"o-field\\"><label class=\\"o-field__label\\">Password</label>
|
||||
<div class=\\"o-ctrl-input\\"><input aria-required=\\"true\\" required=\\"\\" minlength=\\"6\\" class=\\"o-input o-input-iconspace-right\\" type=\\"password\\" autocomplete=\\"off\\">
|
||||
<!--v-if--><span class=\\"o-icon o-icon--clickable o-input__icon-right\\"><i class=\\"mdi mdi-eye mdi-24px\\"></i></span>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<div class=\\"o-field\\"><label class=\\"o-field__label\\">Password (confirmation)</label>
|
||||
<div class=\\"o-ctrl-input\\"><input aria-required=\\"true\\" required=\\"\\" minlength=\\"6\\" class=\\"o-input o-input-iconspace-right\\" type=\\"password\\" autocomplete=\\"off\\">
|
||||
<!--v-if--><span class=\\"o-icon o-icon--clickable o-input__icon-right\\"><i class=\\"mdi mdi-eye mdi-24px\\"></i></span>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
<!--v-if-->
|
||||
</div><button class=\\"button is-primary\\">Reset my password</button>
|
||||
</form>
|
||||
</section>"
|
||||
`;
|
||||
|
||||
exports[`Reset page shows error if token is invalid 1`] = `
|
||||
<section class="section container">
|
||||
<div class="columns is-mobile is-centered">
|
||||
<div class="column is-half-desktop">
|
||||
<h1 class="title">
|
||||
Password reset
|
||||
</h1>
|
||||
<transition-stub name="fade">
|
||||
<article class="message is-danger">
|
||||
<header class="message-header">
|
||||
<p>Error</p><button type="button" class="delete"></button>
|
||||
</header>
|
||||
<section class="message-body">
|
||||
<div class="media">
|
||||
<!---->
|
||||
<div class="media-content">The token you provided is invalid.</div>
|
||||
</div>
|
||||
</section>
|
||||
<!---->
|
||||
</article>
|
||||
</transition-stub>
|
||||
<form>
|
||||
<div class="field"><label class="label">Password</label>
|
||||
<div class="control has-icons-right is-clearfix"><input type="password" autocomplete="on" aria-required="true" required="required" minlength="6" class="input">
|
||||
<!----><span class="icon is-right has-text-primary is-clickable"><i class="mdi mdi-eye mdi-24px"></i></span>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
</div>
|
||||
<div class="field"><label class="label">Password (confirmation)</label>
|
||||
<div class="control has-icons-right is-clearfix"><input type="password" autocomplete="on" aria-required="true" required="required" minlength="6" class="input">
|
||||
<!----><span class="icon is-right has-text-primary is-clickable"><i class="mdi mdi-eye mdi-24px"></i></span>
|
||||
<!---->
|
||||
</div>
|
||||
<!---->
|
||||
</div> <button class="button is-primary">
|
||||
Reset my password
|
||||
</button>
|
||||
</form>
|
||||
exports[`Reset page > shows error if token is invalid 1`] = `
|
||||
"<section class=\\"container mx-auto\\">
|
||||
<h1 class=\\"\\">Password reset</h1>
|
||||
<transition-stub title=\\"Error\\">
|
||||
<article class=\\"o-notification o-notification--danger\\">
|
||||
<!--v-if-->
|
||||
<!--v-if-->
|
||||
<div class=\\"o-notification__wrapper\\">
|
||||
<!--v-if-->
|
||||
<div class=\\"o-notification__content\\">The token you provided is invalid.</div>
|
||||
</div>
|
||||
</article>
|
||||
</transition-stub>
|
||||
<form>
|
||||
<div class=\\"o-field o-field--filled\\"><label class=\\"o-field__label\\">Password</label>
|
||||
<div class=\\"o-ctrl-input\\"><input aria-required=\\"true\\" required=\\"\\" minlength=\\"6\\" class=\\"o-input o-input-iconspace-right\\" type=\\"password\\" autocomplete=\\"off\\">
|
||||
<!--v-if--><span class=\\"o-icon o-icon--clickable o-input__icon-right\\"><i class=\\"mdi mdi-eye mdi-24px\\"></i></span>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<div class=\\"o-field o-field--filled\\"><label class=\\"o-field__label\\">Password (confirmation)</label>
|
||||
<div class=\\"o-ctrl-input\\"><input aria-required=\\"true\\" required=\\"\\" minlength=\\"6\\" class=\\"o-input o-input-iconspace-right\\" type=\\"password\\" autocomplete=\\"off\\">
|
||||
<!--v-if--><span class=\\"o-icon o-icon--clickable o-input__icon-right\\"><i class=\\"mdi mdi-eye mdi-24px\\"></i></span>
|
||||
<!--v-if-->
|
||||
</div>
|
||||
<!--v-if-->
|
||||
</div><button class=\\"button is-primary\\">Reset my password</button>
|
||||
</form>
|
||||
</section>"
|
||||
`;
|
||||
|
||||
@@ -1,86 +1,83 @@
|
||||
import { config, createLocalVue, mount, Wrapper } from "@vue/test-utils";
|
||||
import Login from "@/views/User/Login.vue";
|
||||
import Buefy from "buefy";
|
||||
const useRouterMock = vi.fn(() => ({
|
||||
push: () => {},
|
||||
replace: () => {},
|
||||
}));
|
||||
const useRouteMock = vi.fn(() => {});
|
||||
|
||||
import { config, mount, VueWrapper } from "@vue/test-utils";
|
||||
import Login from "@/views/User/LoginView.vue";
|
||||
import {
|
||||
createMockClient,
|
||||
MockApolloClient,
|
||||
RequestHandler,
|
||||
} from "mock-apollo-client";
|
||||
import VueApollo from "@vue/apollo-option";
|
||||
import buildCurrentUserResolver from "@/apollo/user";
|
||||
import { configMock } from "../../mocks/config";
|
||||
import { i18n } from "@/utils/i18n";
|
||||
import { CONFIG } from "@/graphql/config";
|
||||
import { loginMock as loginConfigMock } from "../../mocks/config";
|
||||
import { LOGIN_CONFIG } from "@/graphql/config";
|
||||
import { loginMock, loginResponseMock } from "../../mocks/auth";
|
||||
import { LOGIN } from "@/graphql/auth";
|
||||
import { CURRENT_USER_CLIENT } from "@/graphql/user";
|
||||
import { ICurrentUser } from "@/types/current-user.model";
|
||||
import flushPromises from "flush-promises";
|
||||
import RouteName from "@/router/name";
|
||||
import { InMemoryCache } from "@apollo/client/cache";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { DefaultApolloClient } from "@vue/apollo-composable";
|
||||
import Oruga from "@oruga-ui/oruga-next";
|
||||
import { cache } from "@/apollo/memory";
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Buefy);
|
||||
config.mocks.$t = (key: string): string => key;
|
||||
const $router = { push: jest.fn(), replace: jest.fn() };
|
||||
vi.mock("vue-router/dist/vue-router.mjs", () => ({
|
||||
useRouter: useRouterMock,
|
||||
useRoute: useRouteMock,
|
||||
}));
|
||||
|
||||
config.global.plugins.push(Oruga);
|
||||
|
||||
describe("Render login form", () => {
|
||||
let wrapper: Wrapper<Vue>;
|
||||
let wrapper: VueWrapper;
|
||||
let mockClient: MockApolloClient | null;
|
||||
let apolloProvider;
|
||||
let requestHandlers: Record<string, RequestHandler>;
|
||||
|
||||
const generateWrapper = (
|
||||
handlers: Record<string, unknown> = {},
|
||||
customProps: Record<string, unknown> = {},
|
||||
baseData: Record<string, unknown> = {},
|
||||
customMocks: Record<string, unknown> = {}
|
||||
) => {
|
||||
const cache = new InMemoryCache({ addTypename: false });
|
||||
|
||||
mockClient = createMockClient({
|
||||
cache,
|
||||
resolvers: buildCurrentUserResolver(cache),
|
||||
});
|
||||
|
||||
requestHandlers = {
|
||||
configQueryHandler: jest.fn().mockResolvedValue(configMock),
|
||||
loginMutationHandler: jest.fn().mockResolvedValue(loginResponseMock),
|
||||
configQueryHandler: vi.fn().mockResolvedValue(loginConfigMock),
|
||||
loginMutationHandler: vi.fn().mockResolvedValue(loginResponseMock),
|
||||
...handlers,
|
||||
};
|
||||
mockClient.setRequestHandler(CONFIG, requestHandlers.configQueryHandler);
|
||||
mockClient.setRequestHandler(
|
||||
LOGIN_CONFIG,
|
||||
requestHandlers.configQueryHandler
|
||||
);
|
||||
mockClient.setRequestHandler(LOGIN, requestHandlers.loginMutationHandler);
|
||||
|
||||
apolloProvider = new VueApollo({
|
||||
defaultClient: mockClient,
|
||||
});
|
||||
|
||||
wrapper = mount(Login, {
|
||||
localVue,
|
||||
i18n,
|
||||
apolloProvider,
|
||||
propsData: {
|
||||
props: {
|
||||
...customProps,
|
||||
},
|
||||
mocks: {
|
||||
$route: { query: {} },
|
||||
$router,
|
||||
...customMocks,
|
||||
},
|
||||
stubs: ["router-link", "router-view"],
|
||||
data() {
|
||||
return {
|
||||
...baseData,
|
||||
};
|
||||
global: {
|
||||
provide: {
|
||||
[DefaultApolloClient]: mockClient,
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
wrapper?.unmount();
|
||||
cache.reset();
|
||||
mockClient = null;
|
||||
apolloProvider = null;
|
||||
$router.push.mockReset();
|
||||
});
|
||||
|
||||
it("requires email and password to be filled", async () => {
|
||||
@@ -90,10 +87,9 @@ describe("Render login form", () => {
|
||||
|
||||
expect(wrapper.exists()).toBe(true);
|
||||
expect(requestHandlers.configQueryHandler).toHaveBeenCalled();
|
||||
expect(wrapper.vm.$apollo.queries.config).toBeTruthy();
|
||||
wrapper.find('form input[type="email"]').setValue("");
|
||||
wrapper.find('form input[type="password"]').setValue("");
|
||||
wrapper.find("form button.button").trigger("click");
|
||||
wrapper.find('form button[type="submit"]').trigger("click");
|
||||
const form = wrapper.find("form");
|
||||
expect(form.exists()).toBe(true);
|
||||
const formElement = form.element as HTMLFormElement;
|
||||
@@ -101,13 +97,18 @@ describe("Render login form", () => {
|
||||
});
|
||||
|
||||
it("renders and submits the login form", async () => {
|
||||
const replace = vi.fn(); // needs to write this code before render()
|
||||
const push = vi.fn();
|
||||
useRouterMock.mockImplementationOnce(() => ({
|
||||
replace,
|
||||
push,
|
||||
}));
|
||||
generateWrapper();
|
||||
await wrapper.vm.$nextTick();
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
expect(wrapper.exists()).toBe(true);
|
||||
expect(requestHandlers.configQueryHandler).toHaveBeenCalled();
|
||||
expect(wrapper.vm.$apollo.queries.config).toBeTruthy();
|
||||
wrapper.find('form input[type="email"]').setValue("some@email.tld");
|
||||
wrapper.find('form input[type="password"]').setValue("somepassword");
|
||||
wrapper.find("form").trigger("submit");
|
||||
@@ -125,14 +126,19 @@ describe("Render login form", () => {
|
||||
await flushPromises();
|
||||
expect(currentUser?.email).toBe("some@email.tld");
|
||||
expect(currentUser?.id).toBe("1");
|
||||
expect(jest.isMockFunction(wrapper.vm.$router.replace)).toBe(true);
|
||||
await flushPromises();
|
||||
expect($router.replace).toHaveBeenCalledWith({ name: RouteName.HOME });
|
||||
expect(replace).toHaveBeenCalledWith({ name: RouteName.HOME });
|
||||
});
|
||||
|
||||
it("handles a login error", async () => {
|
||||
const replace = vi.fn(); // needs to write this code before render()
|
||||
const push = vi.fn();
|
||||
useRouterMock.mockImplementationOnce(() => ({
|
||||
push,
|
||||
replace,
|
||||
}));
|
||||
generateWrapper({
|
||||
loginMutationHandler: jest.fn().mockResolvedValue({
|
||||
loginMutationHandler: vi.fn().mockResolvedValue({
|
||||
errors: [
|
||||
{
|
||||
message:
|
||||
@@ -147,7 +153,6 @@ describe("Render login form", () => {
|
||||
|
||||
expect(wrapper.exists()).toBe(true);
|
||||
expect(requestHandlers.configQueryHandler).toHaveBeenCalled();
|
||||
expect(wrapper.vm.$apollo.queries.config).toBeTruthy();
|
||||
wrapper.find('form input[type="email"]').setValue("some@email.tld");
|
||||
wrapper.find('form input[type="password"]').setValue("somepassword");
|
||||
wrapper.find("form").trigger("submit");
|
||||
@@ -156,21 +161,23 @@ describe("Render login form", () => {
|
||||
...loginMock,
|
||||
});
|
||||
await flushPromises();
|
||||
expect(wrapper.find("article.message.is-danger").text()).toContain(
|
||||
expect(wrapper.find(".o-notification--danger").text()).toContain(
|
||||
"Impossible to authenticate, either your email or password are invalid."
|
||||
);
|
||||
expect($router.push).not.toHaveBeenCalled();
|
||||
expect(push).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("handles redirection after login", async () => {
|
||||
generateWrapper(
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{
|
||||
$route: { query: { redirect: "/about/instance" } },
|
||||
}
|
||||
);
|
||||
const replace = vi.fn(); // needs to write this code before render()
|
||||
const push = vi.fn();
|
||||
useRouterMock.mockImplementationOnce(() => ({
|
||||
replace,
|
||||
push,
|
||||
}));
|
||||
useRouteMock.mockImplementationOnce(() => ({
|
||||
query: { redirect: "/about/instance" },
|
||||
}));
|
||||
generateWrapper();
|
||||
|
||||
await wrapper.vm.$nextTick();
|
||||
await wrapper.vm.$nextTick();
|
||||
@@ -179,6 +186,6 @@ describe("Render login form", () => {
|
||||
wrapper.find('form input[type="password"]').setValue("somepassword");
|
||||
wrapper.find("form").trigger("submit");
|
||||
await flushPromises();
|
||||
expect($router.push).toHaveBeenCalledWith("/about/instance");
|
||||
expect(push).toHaveBeenCalledWith("/about/instance");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,3 +1,194 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`App component renders a Vue component 1`] = `<b-navbar-stub type="is-secondary" wrapperclass="container" closeonclick="true" mobileburger="true" id="navbar"><template></template> <template></template> <template></template></b-navbar-stub>`;
|
||||
exports[`App component > renders a Vue component 1`] = `
|
||||
"<nav class=\\"bg-white border-gray-200 px-2 sm:px-4 py-2.5 dark:bg-gray-900\\" data-v-4295d220=\\"\\">
|
||||
<div class=\\"container mx-auto flex flex-wrap justify-between items-center mx-auto\\" data-v-4295d220=\\"\\">
|
||||
<router-link to=\\"[object Object]\\" class=\\"flex items-center\\" data-v-4295d220=\\"\\">
|
||||
<logo-stub invert=\\"false\\" class=\\"w-40\\" data-v-4295d220=\\"\\"></logo-stub>
|
||||
</router-link>
|
||||
<!--v-if--><button type=\\"button\\" class=\\"inline-flex items-center p-2 ml-1 text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600\\" aria-controls=\\"mobile-menu-2\\" aria-expanded=\\"false\\" data-v-4295d220=\\"\\"><span class=\\"sr-only\\" data-v-4295d220=\\"\\">Open main menu</span><svg class=\\"w-6 h-6\\" aria-hidden=\\"true\\" fill=\\"currentColor\\" viewBox=\\"0 0 20 20\\" xmlns=\\"http://www.w3.org/2000/svg\\" data-v-4295d220=\\"\\">
|
||||
<path fill-rule=\\"evenodd\\" d=\\"M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z\\" clip-rule=\\"evenodd\\" data-v-4295d220=\\"\\"></path>
|
||||
</svg></button>
|
||||
<div class=\\"justify-between items-center w-full md:flex md:w-auto md:order-1 hidden\\" id=\\"mobile-menu-2\\" data-v-4295d220=\\"\\">
|
||||
<ul class=\\"flex flex-col md:flex-row md:space-x-8 mt-2 md:mt-0 md:text-sm md:font-medium\\" data-v-4295d220=\\"\\">
|
||||
<li data-v-4295d220=\\"\\">
|
||||
<router-link to=\\"[object Object]\\" class=\\"block py-2 pr-4 pl-3 text-gray-700 border-b border-gray-100 hover:bg-gray-50 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-gray-400 md:dark:hover:text-white dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent dark:border-gray-700\\" data-v-4295d220=\\"\\">Login</router-link>
|
||||
</li>
|
||||
<li data-v-4295d220=\\"\\">
|
||||
<router-link to=\\"[object Object]\\" class=\\"block py-2 pr-4 pl-3 text-gray-700 border-b border-gray-100 hover:bg-gray-50 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-gray-400 md:dark:hover:text-white dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent dark:border-gray-700\\" data-v-4295d220=\\"\\">Register</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<!-- <o-navbar
|
||||
id=\\"navbar\\"
|
||||
type=\\"is-secondary\\"
|
||||
wrapper-class=\\"container mx-auto\\"
|
||||
v-model:active=\\"mobileNavbarActive\\"
|
||||
>
|
||||
<template #brand>
|
||||
<o-navbar-item
|
||||
tag=\\"router-link\\"
|
||||
:to=\\"{ name: RouteName.HOME }\\"
|
||||
:aria-label=\\"$t('Home')\\"
|
||||
>
|
||||
<logo />
|
||||
</o-navbar-item>
|
||||
</template>
|
||||
<template #start>
|
||||
<o-navbar-item tag=\\"router-link\\" :to=\\"{ name: RouteName.SEARCH }\\">{{
|
||||
$t(\\"Explore\\")
|
||||
}}</o-navbar-item>
|
||||
<o-navbar-item
|
||||
v-if=\\"currentActor.id && currentUser?.isLoggedIn\\"
|
||||
tag=\\"router-link\\"
|
||||
:to=\\"{ name: RouteName.MY_EVENTS }\\"
|
||||
>{{ $t(\\"My events\\") }}</o-navbar-item
|
||||
>
|
||||
<o-navbar-item
|
||||
tag=\\"router-link\\"
|
||||
:to=\\"{ name: RouteName.MY_GROUPS }\\"
|
||||
v-if=\\"
|
||||
config &&
|
||||
config.features.groups &&
|
||||
currentActor.id &&
|
||||
currentUser?.isLoggedIn
|
||||
\\"
|
||||
>{{ $t(\\"My groups\\") }}</o-navbar-item
|
||||
>
|
||||
<o-navbar-item
|
||||
tag=\\"span\\"
|
||||
v-if=\\"
|
||||
config &&
|
||||
config.features.eventCreation &&
|
||||
currentActor.id &&
|
||||
currentUser?.isLoggedIn
|
||||
\\"
|
||||
>
|
||||
<o-button
|
||||
v-if=\\"!hideCreateEventsButton\\"
|
||||
tag=\\"router-link\\"
|
||||
:to=\\"{ name: RouteName.CREATE_EVENT }\\"
|
||||
variant=\\"primary\\"
|
||||
>{{ $t(\\"Create\\") }}</o-button
|
||||
>
|
||||
</o-navbar-item>
|
||||
</template>
|
||||
<template #end>
|
||||
<o-navbar-item tag=\\"div\\">
|
||||
<search-field @navbar-search=\\"mobileNavbarActive = false\\" />
|
||||
</o-navbar-item>
|
||||
|
||||
<o-navbar-dropdown
|
||||
v-if=\\"currentActor.id && currentUser?.isLoggedIn\\"
|
||||
right
|
||||
collapsible
|
||||
ref=\\"user-dropdown\\"
|
||||
tabindex=\\"0\\"
|
||||
tag=\\"span\\"
|
||||
@keyup.enter=\\"toggleMenu\\"
|
||||
>
|
||||
<template #label v-if=\\"currentActor\\">
|
||||
<div class=\\"identity-wrapper\\">
|
||||
<div>
|
||||
<figure class=\\"image is-32x32\\" v-if=\\"currentActor.avatar\\">
|
||||
<img
|
||||
class=\\"is-rounded\\"
|
||||
alt=\\"avatarUrl\\"
|
||||
:src=\\"currentActor.avatar.url\\"
|
||||
/>
|
||||
</figure>
|
||||
<o-icon v-else icon=\\"account-circle\\" />
|
||||
</div>
|
||||
<div class=\\"media-content is-hidden-desktop\\">
|
||||
<span>{{ displayName(currentActor) }}</span>
|
||||
<span class=\\"has-text-grey-dark\\" v-if=\\"currentActor.name\\"
|
||||
>@{{ currentActor.preferredUsername }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
No identities dropdown if no identities
|
||||
<span v-if=\\"identities.length <= 1\\"></span>
|
||||
<o-navbar-item
|
||||
tag=\\"span\\"
|
||||
v-for=\\"identity in identities\\"
|
||||
v-else
|
||||
:active=\\"identity.id === currentActor.id\\"
|
||||
:key=\\"identity.id\\"
|
||||
tabindex=\\"0\\"
|
||||
@click=\\"setIdentity({
|
||||
preferredUsername: identity.preferredUsername,
|
||||
})\\"
|
||||
@keyup.enter=\\"setIdentity({
|
||||
preferredUsername: identity.preferredUsername,
|
||||
})\\"
|
||||
>
|
||||
<span>
|
||||
<div class=\\"media-left\\">
|
||||
<figure class=\\"image is-32x32\\" v-if=\\"identity.avatar\\">
|
||||
<img
|
||||
class=\\"is-rounded\\"
|
||||
loading=\\"lazy\\"
|
||||
:src=\\"identity.avatar.url\\"
|
||||
alt
|
||||
/>
|
||||
</figure>
|
||||
<o-icon v-else size=\\"is-medium\\" icon=\\"account-circle\\" />
|
||||
</div>
|
||||
|
||||
<div class=\\"media-content\\">
|
||||
<span>{{ displayName(identity) }}</span>
|
||||
<span class=\\"has-text-grey-dark\\" v-if=\\"identity.name\\"
|
||||
>@{{ identity.preferredUsername }}</span
|
||||
>
|
||||
</div>
|
||||
</span>
|
||||
|
||||
<hr class=\\"navbar-divider\\" role=\\"presentation\\" />
|
||||
</o-navbar-item>
|
||||
|
||||
<o-navbar-item
|
||||
tag=\\"router-link\\"
|
||||
:to=\\"{ name: RouteName.UPDATE_IDENTITY }\\"
|
||||
>{{ $t(\\"My account\\") }}</o-navbar-item
|
||||
>
|
||||
<o-navbar-item
|
||||
v-if=\\"currentUser.role === ICurrentUserRole.ADMINISTRATOR\\"
|
||||
tag=\\"router-link\\"
|
||||
:to=\\"{ name: RouteName.ADMIN_DASHBOARD }\\"
|
||||
>{{ $t(\\"Administration\\") }}</o-navbar-item
|
||||
>
|
||||
|
||||
<o-navbar-item
|
||||
tag=\\"span\\"
|
||||
tabindex=\\"0\\"
|
||||
@click=\\"logout\\"
|
||||
@keyup.enter=\\"logout\\"
|
||||
>
|
||||
<span>{{ $t(\\"Log out\\") }}</span>
|
||||
</o-navbar-item>
|
||||
</o-navbar-dropdown>
|
||||
|
||||
<o-navbar-item v-else tag=\\"div\\">
|
||||
<div class=\\"buttons\\">
|
||||
<router-link
|
||||
class=\\"button is-primary\\"
|
||||
v-if=\\"config && config.registrationsOpen\\"
|
||||
:to=\\"{ name: RouteName.REGISTER }\\"
|
||||
>
|
||||
<strong>{{ $t(\\"Sign up\\") }}</strong>
|
||||
</router-link>
|
||||
|
||||
<router-link
|
||||
class=\\"button is-light\\"
|
||||
:to=\\"{ name: RouteName.LOGIN }\\"
|
||||
>{{ $t(\\"Log in\\") }}</router-link
|
||||
>
|
||||
</div>
|
||||
</o-navbar-item>
|
||||
</template>
|
||||
</o-navbar> -->"
|
||||
`;
|
||||
|
||||
@@ -1,30 +1,29 @@
|
||||
import { shallowMount, createLocalVue, Wrapper, config } from "@vue/test-utils";
|
||||
const useRouterMock = vi.fn(() => ({
|
||||
push: () => {},
|
||||
}));
|
||||
|
||||
import { shallowMount, VueWrapper } from "@vue/test-utils";
|
||||
import NavBar from "@/components/NavBar.vue";
|
||||
import {
|
||||
createMockClient,
|
||||
MockApolloClient,
|
||||
RequestHandler,
|
||||
} from "mock-apollo-client";
|
||||
import VueApollo from "@vue/apollo-option";
|
||||
import { CONFIG } from "@/graphql/config";
|
||||
import { USER_SETTINGS } from "@/graphql/user";
|
||||
import buildCurrentUserResolver from "@/apollo/user";
|
||||
import Buefy from "buefy";
|
||||
import { configMock } from "../mocks/config";
|
||||
import { InMemoryCache } from "@apollo/client/cache";
|
||||
import { describe, it, vi, expect, afterEach } from "vitest";
|
||||
import { DefaultApolloClient } from "@vue/apollo-composable";
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(VueApollo);
|
||||
localVue.use(Buefy);
|
||||
config.mocks.$t = (key: string): string => key;
|
||||
vi.mock("vue-router/dist/vue-router.mjs", () => ({
|
||||
useRouter: useRouterMock,
|
||||
}));
|
||||
|
||||
describe("App component", () => {
|
||||
let wrapper: Wrapper<Vue>;
|
||||
let wrapper: VueWrapper;
|
||||
let mockClient: MockApolloClient | null;
|
||||
let apolloProvider;
|
||||
let requestHandlers: Record<string, RequestHandler>;
|
||||
|
||||
const createComponent = (handlers = {}, baseData = {}) => {
|
||||
const createComponent = (handlers = {}) => {
|
||||
const cache = new InMemoryCache({ addTypename: false });
|
||||
|
||||
mockClient = createMockClient({
|
||||
@@ -32,50 +31,34 @@ describe("App component", () => {
|
||||
resolvers: buildCurrentUserResolver(cache),
|
||||
});
|
||||
|
||||
requestHandlers = {
|
||||
configQueryHandler: jest.fn().mockResolvedValue(configMock),
|
||||
loggedUserQueryHandler: jest.fn().mockResolvedValue(null),
|
||||
...handlers,
|
||||
};
|
||||
|
||||
mockClient.setRequestHandler(CONFIG, requestHandlers.configQueryHandler);
|
||||
|
||||
mockClient.setRequestHandler(
|
||||
USER_SETTINGS,
|
||||
requestHandlers.loggedUserQueryHandler
|
||||
);
|
||||
|
||||
apolloProvider = new VueApollo({
|
||||
defaultClient: mockClient,
|
||||
});
|
||||
requestHandlers = { ...handlers };
|
||||
|
||||
wrapper = shallowMount(NavBar, {
|
||||
localVue,
|
||||
apolloProvider,
|
||||
stubs: ["router-link", "router-view"],
|
||||
data() {
|
||||
return {
|
||||
...baseData,
|
||||
};
|
||||
// stubs: ["router-link", "router-view", "o-dropdown", "o-dropdown-item"],
|
||||
global: {
|
||||
provide: {
|
||||
[DefaultApolloClient]: mockClient,
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
wrapper?.unmount();
|
||||
mockClient = null;
|
||||
apolloProvider = null;
|
||||
});
|
||||
|
||||
it("renders a Vue component", async () => {
|
||||
const push = vi.fn();
|
||||
useRouterMock.mockImplementationOnce(() => ({
|
||||
push,
|
||||
}));
|
||||
createComponent();
|
||||
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
expect(wrapper.exists()).toBe(true);
|
||||
expect(requestHandlers.configQueryHandler).toHaveBeenCalled();
|
||||
expect(wrapper.vm.$apollo.queries.config).toBeTruthy();
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
expect(wrapper.findComponent({ name: "b-navbar" }).exists()).toBeTruthy();
|
||||
// expect(wrapper.findComponent({ name: "b-navbar" }).exists()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { mount } from "@vue/test-utils";
|
||||
import Tag from "@/components/Tag.vue";
|
||||
import { it, expect } from "vitest";
|
||||
|
||||
const tagContent = "My tag";
|
||||
|
||||
@@ -15,5 +16,5 @@ it("renders a Vue component", () => {
|
||||
const wrapper = createComponent();
|
||||
|
||||
expect(wrapper.exists()).toBe(true);
|
||||
expect(wrapper.find("span.tag span").text()).toEqual(tagContent);
|
||||
expect(wrapper.find("span").text()).toEqual(tagContent);
|
||||
});
|
||||
|
||||
@@ -127,3 +127,28 @@ export const configMock = {
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const loginMock = {
|
||||
data: {
|
||||
config: {
|
||||
__typename: "Config",
|
||||
auth: {
|
||||
__typename: "Auth",
|
||||
oauthProviders: [],
|
||||
},
|
||||
registrationsOpen: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const anonymousActorIdMock = {
|
||||
data: {
|
||||
config: {
|
||||
__typename: "Config",
|
||||
anonymous: {
|
||||
__typename: "Anonymous",
|
||||
actorId: "1",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -15,11 +15,7 @@ export const fetchEventBasicMock = {
|
||||
__typename: "ParticipantStats",
|
||||
notApproved: 0,
|
||||
notConfirmed: 0,
|
||||
rejected: 0,
|
||||
participant: 0,
|
||||
creator: 1,
|
||||
moderator: 0,
|
||||
administrator: 0,
|
||||
going: 1,
|
||||
},
|
||||
},
|
||||
@@ -61,7 +57,7 @@ export const joinEventMock = {
|
||||
email: "some@email.tld",
|
||||
message: "a message long enough",
|
||||
locale: "en_US",
|
||||
timezone: "UTC",
|
||||
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||
};
|
||||
|
||||
export const eventNoCommentThreadsMock = {
|
||||
@@ -152,8 +148,9 @@ export const eventCommentThreadsMock = {
|
||||
export const newCommentForEventMock = {
|
||||
eventId: "1",
|
||||
text: "my new comment",
|
||||
inReplyToCommentId: null,
|
||||
inReplyToCommentId: undefined,
|
||||
isAnnouncement: false,
|
||||
originCommentId: undefined,
|
||||
};
|
||||
|
||||
export const newCommentForEventResponse: DataMock = {
|
||||
|
||||
26
js/tests/unit/specs/mocks/matchMedia.ts
Normal file
26
js/tests/unit/specs/mocks/matchMedia.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { vi } from "vitest";
|
||||
|
||||
window.matchMedia = vi.fn().mockImplementation((query) => ({
|
||||
matches: false,
|
||||
media: query,
|
||||
onchange: null,
|
||||
addListener: vi.fn(), // deprecated
|
||||
removeListener: vi.fn(), // deprecated
|
||||
addEventListener: vi.fn(),
|
||||
removeEventListener: vi.fn(),
|
||||
dispatchEvent: vi.fn(),
|
||||
}));
|
||||
|
||||
// Object.defineProperty(window, "matchMedia", {
|
||||
// writable: true,
|
||||
// value: vi.fn().mockImplementation((query) => ({
|
||||
// matches: false,
|
||||
// media: query,
|
||||
// onchange: null,
|
||||
// addListener: vi.fn(), // deprecated
|
||||
// removeListener: vi.fn(), // deprecated
|
||||
// addEventListener: vi.fn(),
|
||||
// removeEventListener: vi.fn(),
|
||||
// dispatchEvent: vi.fn(),
|
||||
// })),
|
||||
// });
|
||||
Reference in New Issue
Block a user