diff --git a/.tool-versions b/.tool-versions
index cc71c9225..89a61338e 100644
--- a/.tool-versions
+++ b/.tool-versions
@@ -1,4 +1,4 @@
erlang 26.2.2
elixir 1.16.1-otp-26
-nodejs 18.19.1
+nodejs 24.9.0
python 3.13.1-v3
diff --git a/tests/unit/specs/common.ts b/tests/unit/specs/common.ts
index 03c4853aa..3f0067426 100644
--- a/tests/unit/specs/common.ts
+++ b/tests/unit/specs/common.ts
@@ -71,6 +71,7 @@ export function defaultResolvers(
export function htmlRemoveId(htmlText: string) {
return htmlText
.replaceAll(/ id="[a-z0-9]+" /gi, ' id="" ')
+ .replaceAll(/ aria-controls="[a-z0-9]+" /gi, ' aria-controls="" ')
.replaceAll(/ for="[a-z0-9]+"/gi, ' for=""');
}
diff --git a/tests/unit/specs/components/Group/CreateView.spec.ts b/tests/unit/specs/components/Group/CreateView.spec.ts
new file mode 100644
index 000000000..376c3fd76
--- /dev/null
+++ b/tests/unit/specs/components/Group/CreateView.spec.ts
@@ -0,0 +1,49 @@
+import { beforeEach, describe, it, expect } from "vitest";
+import { enUS } from "date-fns/locale";
+import { routes } from "@/router";
+import { createRouter, createWebHistory, Router } from "vue-router";
+import { config, mount } from "@vue/test-utils";
+import { Oruga } from "@oruga-ui/oruga-next";
+import flushPromises from "flush-promises";
+import { getMockClient, requestHandlers } from "../../mocks/client";
+import { htmlRemoveId } from "../../common";
+import CreateView from "@/views/Group/CreateView.vue";
+import { CREATE_GROUP } from "@/graphql/group";
+
+config.global.plugins.push(Oruga);
+
+let router: Router;
+
+beforeEach(async () => {
+ router = createRouter({
+ history: createWebHistory(),
+ routes: routes,
+ });
+
+ // await router.isReady();
+});
+
+const generateWrapper = () => {
+ const global_data = getMockClient([CREATE_GROUP]);
+ global_data.provide.dateFnsLocale = enUS;
+ global_data.plugins = [router];
+ return mount(CreateView, {
+ props: {},
+ global: {
+ ...global_data,
+ stubs: {
+ RouterLink: false,
+ },
+ },
+ });
+};
+
+describe("CreateView", () => {
+ it("Show simple", async () => {
+ const wrapper = generateWrapper();
+ await wrapper.vm.$nextTick();
+ await flushPromises();
+ expect(htmlRemoveId(wrapper.html())).toMatchSnapshot();
+ expect(requestHandlers.handle_0).toHaveBeenCalledTimes(0);
+ });
+});
diff --git a/tests/unit/specs/components/Group/GroupFollowers.spec.ts b/tests/unit/specs/components/Group/GroupFollowers.spec.ts
new file mode 100644
index 000000000..67129fb8b
--- /dev/null
+++ b/tests/unit/specs/components/Group/GroupFollowers.spec.ts
@@ -0,0 +1,58 @@
+import { beforeEach, describe, it, expect } from "vitest";
+import { enUS } from "date-fns/locale";
+import { routes } from "@/router";
+import { createRouter, createWebHistory, Router } from "vue-router";
+import { config, mount } from "@vue/test-utils";
+import { Oruga } from "@oruga-ui/oruga-next";
+import flushPromises from "flush-promises";
+import { getMockClient, requestHandlers } from "../../mocks/client";
+import { htmlRemoveId } from "../../common";
+import GroupFollowers from "@/views/Group/GroupFollowers.vue";
+import { GROUP_FOLLOWERS, UPDATE_FOLLOWER } from "@/graphql/followers";
+
+config.global.plugins.push(Oruga);
+
+let router: Router;
+
+beforeEach(async () => {
+ router = createRouter({
+ history: createWebHistory(),
+ routes: routes,
+ });
+
+ // await router.isReady();
+});
+
+const generateWrapper = () => {
+ const global_data = getMockClient([GROUP_FOLLOWERS, UPDATE_FOLLOWER]);
+ global_data.provide.dateFnsLocale = enUS;
+ global_data.plugins = [router];
+ return mount(GroupFollowers, {
+ props: {
+ preferredUsername: "my-group",
+ },
+ global: {
+ ...global_data,
+ stubs: {
+ RouterLink: false,
+ },
+ },
+ });
+};
+
+describe("GroupFollowers", () => {
+ it("Show simple", async () => {
+ const wrapper = generateWrapper();
+ await wrapper.vm.$nextTick();
+ await flushPromises();
+ expect(htmlRemoveId(wrapper.html())).toMatchSnapshot();
+ expect(requestHandlers.handle_0).toHaveBeenCalledTimes(1);
+ expect(requestHandlers.handle_1).toHaveBeenCalledTimes(0);
+ expect(requestHandlers.handle_0).toHaveBeenCalledWith({
+ approved: true,
+ followersLimit: 10,
+ followersPage: 1,
+ name: "my-group",
+ });
+ });
+});
diff --git a/tests/unit/specs/components/Group/GroupMembers.spec.ts b/tests/unit/specs/components/Group/GroupMembers.spec.ts
new file mode 100644
index 000000000..6e4f51a8a
--- /dev/null
+++ b/tests/unit/specs/components/Group/GroupMembers.spec.ts
@@ -0,0 +1,73 @@
+import { beforeEach, describe, it, expect } from "vitest";
+import { enUS } from "date-fns/locale";
+import { routes } from "@/router";
+import { createRouter, createWebHistory, Router } from "vue-router";
+import { config, mount } from "@vue/test-utils";
+import { Oruga } from "@oruga-ui/oruga-next";
+import flushPromises from "flush-promises";
+import { getMockClient, requestHandlers } from "../../mocks/client";
+import { htmlRemoveId } from "../../common";
+import GroupMembers from "@/views/Group/GroupMembers.vue";
+import {
+ INVITE_MEMBER,
+ GROUP_MEMBERS,
+ REMOVE_MEMBER,
+ UPDATE_MEMBER,
+ APPROVE_MEMBER,
+} from "@/graphql/member";
+
+config.global.plugins.push(Oruga);
+
+let router: Router;
+
+beforeEach(async () => {
+ router = createRouter({
+ history: createWebHistory(),
+ routes: routes,
+ });
+
+ // await router.isReady();
+});
+
+const generateWrapper = () => {
+ const global_data = getMockClient([
+ INVITE_MEMBER,
+ GROUP_MEMBERS,
+ REMOVE_MEMBER,
+ UPDATE_MEMBER,
+ APPROVE_MEMBER,
+ ]);
+ global_data.provide.dateFnsLocale = enUS;
+ global_data.plugins = [router];
+ return mount(GroupMembers, {
+ props: {
+ preferredUsername: "my-group",
+ },
+ global: {
+ ...global_data,
+ stubs: {
+ RouterLink: false,
+ },
+ },
+ });
+};
+
+describe("GroupMembers", () => {
+ it("Show simple", async () => {
+ const wrapper = generateWrapper();
+ await wrapper.vm.$nextTick();
+ await flushPromises();
+ expect(htmlRemoveId(wrapper.html())).toMatchSnapshot();
+ expect(requestHandlers.handle_0).toHaveBeenCalledTimes(0);
+ expect(requestHandlers.handle_1).toHaveBeenCalledTimes(1);
+ expect(requestHandlers.handle_2).toHaveBeenCalledTimes(0);
+ expect(requestHandlers.handle_3).toHaveBeenCalledTimes(0);
+ expect(requestHandlers.handle_4).toHaveBeenCalledTimes(0);
+ expect(requestHandlers.handle_1).toHaveBeenCalledWith({
+ groupName: "my-group",
+ limit: 10,
+ page: 1,
+ roles: undefined,
+ });
+ });
+});
diff --git a/tests/unit/specs/components/Group/GroupSettings.spec.ts b/tests/unit/specs/components/Group/GroupSettings.spec.ts
new file mode 100644
index 000000000..ab5a9f4af
--- /dev/null
+++ b/tests/unit/specs/components/Group/GroupSettings.spec.ts
@@ -0,0 +1,56 @@
+import { beforeEach, describe, it, expect } from "vitest";
+import { enUS } from "date-fns/locale";
+import { routes } from "@/router";
+import { createRouter, createWebHistory, Router } from "vue-router";
+import { config, mount } from "@vue/test-utils";
+import { Oruga } from "@oruga-ui/oruga-next";
+import flushPromises from "flush-promises";
+import { getMockClient, requestHandlers } from "../../mocks/client";
+import { htmlRemoveId } from "../../common";
+import GroupSettings from "@/views/Group/GroupSettings.vue";
+import { FETCH_GROUP_PUBLIC } from "@/graphql/group";
+import { DELETE_GROUP } from "@/graphql/group";
+
+config.global.plugins.push(Oruga);
+
+let router: Router;
+
+beforeEach(async () => {
+ router = createRouter({
+ history: createWebHistory(),
+ routes: routes,
+ });
+
+ // await router.isReady();
+});
+
+const generateWrapper = () => {
+ const global_data = getMockClient([FETCH_GROUP_PUBLIC, DELETE_GROUP]);
+ global_data.provide.dateFnsLocale = enUS;
+ global_data.plugins = [router];
+ return mount(GroupSettings, {
+ props: {
+ preferredUsername: "my-group",
+ },
+ global: {
+ ...global_data,
+ stubs: {
+ RouterLink: false,
+ },
+ },
+ });
+};
+
+describe("GroupSettings", () => {
+ it("Show simple", async () => {
+ const wrapper = generateWrapper();
+ await wrapper.vm.$nextTick();
+ await flushPromises();
+ expect(htmlRemoveId(wrapper.html())).toMatchSnapshot();
+ expect(requestHandlers.handle_0).toHaveBeenCalledTimes(1);
+ expect(requestHandlers.handle_1).toHaveBeenCalledTimes(0);
+ expect(requestHandlers.handle_0).toHaveBeenCalledWith({
+ name: "my-group",
+ });
+ });
+});
diff --git a/tests/unit/specs/components/Group/GroupView.spec.ts b/tests/unit/specs/components/Group/GroupView.spec.ts
new file mode 100644
index 000000000..9308d7d7b
--- /dev/null
+++ b/tests/unit/specs/components/Group/GroupView.spec.ts
@@ -0,0 +1,79 @@
+import { beforeEach, describe, it, expect } from "vitest";
+import { enUS } from "date-fns/locale";
+import { routes } from "@/router";
+import { createRouter, createWebHistory, Router } from "vue-router";
+import { config, mount } from "@vue/test-utils";
+import { Oruga } from "@oruga-ui/oruga-next";
+import flushPromises from "flush-promises";
+import { getMockClient, requestHandlers } from "../../mocks/client";
+import { htmlRemoveId } from "../../common";
+import GroupView from "@/views/Group/GroupView.vue";
+import { FETCH_GROUP_PUBLIC } from "@/graphql/group";
+import { JOIN_GROUP } from "@/graphql/member";
+import {
+ GROUP_MEMBERSHIP_SUBSCRIPTION_CHANGED,
+ PERSON_STATUS_GROUP,
+} from "@/graphql/actor";
+import {
+ FOLLOW_GROUP,
+ UNFOLLOW_GROUP,
+ UPDATE_GROUP_FOLLOW,
+} from "@/graphql/followers";
+
+config.global.plugins.push(Oruga);
+
+let router: Router;
+
+beforeEach(async () => {
+ router = createRouter({
+ history: createWebHistory(),
+ routes: routes,
+ });
+
+ // await router.isReady();
+});
+
+const generateWrapper = () => {
+ const global_data = getMockClient([
+ FETCH_GROUP_PUBLIC,
+ JOIN_GROUP,
+ GROUP_MEMBERSHIP_SUBSCRIPTION_CHANGED,
+ PERSON_STATUS_GROUP,
+ FOLLOW_GROUP,
+ UNFOLLOW_GROUP,
+ UPDATE_GROUP_FOLLOW,
+ ]);
+ global_data.provide.dateFnsLocale = enUS;
+ global_data.plugins = [router];
+ return mount(GroupView, {
+ props: {
+ preferredUsername: "my-group",
+ },
+ global: {
+ ...global_data,
+ stubs: {
+ RouterLink: false,
+ },
+ },
+ });
+};
+
+describe("GroupView", () => {
+ it("Show simple", async () => {
+ const wrapper = generateWrapper();
+ await wrapper.vm.$nextTick();
+ await flushPromises();
+ expect(htmlRemoveId(wrapper.html())).toMatchSnapshot();
+ expect(requestHandlers.handle_0).toHaveBeenCalledTimes(1);
+ expect(requestHandlers.handle_1).toHaveBeenCalledTimes(0);
+ expect(requestHandlers.handle_2).toHaveBeenCalledTimes(0);
+ expect(requestHandlers.handle_3).toHaveBeenCalledTimes(0);
+ expect(requestHandlers.handle_4).toHaveBeenCalledTimes(0);
+ expect(requestHandlers.handle_5).toHaveBeenCalledTimes(0);
+ expect(requestHandlers.handle_6).toHaveBeenCalledTimes(0);
+ expect(requestHandlers.handle_0).toHaveBeenCalledWith({
+ name: "my-group",
+ afterDateTime: new Date("2022-02-02T02:04:00.000Z"),
+ });
+ });
+});
diff --git a/tests/unit/specs/components/Group/MyGroups.spec.ts b/tests/unit/specs/components/Group/MyGroups.spec.ts
new file mode 100644
index 000000000..27f83f6d4
--- /dev/null
+++ b/tests/unit/specs/components/Group/MyGroups.spec.ts
@@ -0,0 +1,51 @@
+import { beforeEach, describe, it, expect } from "vitest";
+import { enUS } from "date-fns/locale";
+import { routes } from "@/router";
+import { createRouter, createWebHistory, Router } from "vue-router";
+import { config, mount } from "@vue/test-utils";
+import { Oruga } from "@oruga-ui/oruga-next";
+import flushPromises from "flush-promises";
+import { getMockClient, requestHandlers } from "../../mocks/client";
+import { htmlRemoveId } from "../../common";
+import MyGroups from "@/views/Group/MyGroups.vue";
+import { LOGGED_USER_MEMBERSHIPS } from "@/graphql/actor";
+import { LEAVE_GROUP } from "@/graphql/group";
+
+config.global.plugins.push(Oruga);
+
+let router: Router;
+
+beforeEach(async () => {
+ router = createRouter({
+ history: createWebHistory(),
+ routes: routes,
+ });
+
+ // await router.isReady();
+});
+
+const generateWrapper = () => {
+ const global_data = getMockClient([LOGGED_USER_MEMBERSHIPS, LEAVE_GROUP]);
+ global_data.provide.dateFnsLocale = enUS;
+ global_data.plugins = [router];
+ return mount(MyGroups, {
+ props: {},
+ global: {
+ ...global_data,
+ stubs: {
+ RouterLink: false,
+ },
+ },
+ });
+};
+
+describe("MyGroups", () => {
+ it("Show simple", async () => {
+ const wrapper = generateWrapper();
+ await wrapper.vm.$nextTick();
+ await flushPromises();
+ expect(htmlRemoveId(wrapper.html())).toMatchSnapshot();
+ expect(requestHandlers.handle_0).toHaveBeenCalledTimes(1);
+ expect(requestHandlers.handle_1).toHaveBeenCalledTimes(0);
+ });
+});
diff --git a/tests/unit/specs/components/Group/SettingsView.spec.ts b/tests/unit/specs/components/Group/SettingsView.spec.ts
new file mode 100644
index 000000000..87ed637b4
--- /dev/null
+++ b/tests/unit/specs/components/Group/SettingsView.spec.ts
@@ -0,0 +1,49 @@
+import { beforeEach, describe, it, expect } from "vitest";
+import { enUS } from "date-fns/locale";
+import { routes } from "@/router";
+import { createRouter, createWebHistory, Router } from "vue-router";
+import { config, shallowMount } from "@vue/test-utils";
+import { Oruga } from "@oruga-ui/oruga-next";
+import flushPromises from "flush-promises";
+import { getMockClient } from "../../mocks/client";
+import { htmlRemoveId } from "../../common";
+import SettingsView from "@/views/Group/SettingsView.vue";
+
+config.global.plugins.push(Oruga);
+
+let router: Router;
+
+beforeEach(async () => {
+ router = createRouter({
+ history: createWebHistory(),
+ routes: routes,
+ });
+
+ // await router.isReady();
+});
+
+const generateWrapper = () => {
+ const global_data = getMockClient([]);
+ global_data.provide.dateFnsLocale = enUS;
+ global_data.plugins = [router];
+ return shallowMount(SettingsView, {
+ props: {
+ preferredUsername: "my-group",
+ },
+ global: {
+ ...global_data,
+ stubs: {
+ RouterLink: false,
+ },
+ },
+ });
+};
+
+describe("SettingsView", () => {
+ it("Show simple", async () => {
+ const wrapper = generateWrapper();
+ await wrapper.vm.$nextTick();
+ await flushPromises();
+ expect(htmlRemoveId(wrapper.html())).toMatchSnapshot();
+ });
+});
diff --git a/tests/unit/specs/components/Group/TimelineView.spec.ts b/tests/unit/specs/components/Group/TimelineView.spec.ts
new file mode 100644
index 000000000..047a18aa4
--- /dev/null
+++ b/tests/unit/specs/components/Group/TimelineView.spec.ts
@@ -0,0 +1,49 @@
+import { beforeEach, describe, it, expect } from "vitest";
+import { enUS } from "date-fns/locale";
+import { routes } from "@/router";
+import { createRouter, createWebHistory, Router } from "vue-router";
+import { config, mount } from "@vue/test-utils";
+import { Oruga } from "@oruga-ui/oruga-next";
+import flushPromises from "flush-promises";
+import { getMockClient, requestHandlers } from "../../mocks/client";
+import { htmlRemoveId } from "../../common";
+import TimelineView from "@/views/Group/TimelineView.vue";
+import { GROUP_TIMELINE } from "@/graphql/group";
+
+config.global.plugins.push(Oruga);
+
+let router: Router;
+
+beforeEach(async () => {
+ router = createRouter({
+ history: createWebHistory(),
+ routes: routes,
+ });
+
+ // await router.isReady();
+});
+
+const generateWrapper = () => {
+ const global_data = getMockClient([GROUP_TIMELINE]);
+ global_data.provide.dateFnsLocale = enUS;
+ global_data.plugins = [router];
+ return mount(TimelineView, {
+ props: {},
+ global: {
+ ...global_data,
+ stubs: {
+ RouterLink: false,
+ },
+ },
+ });
+};
+
+describe("TimelineView", () => {
+ it("Show simple", async () => {
+ const wrapper = generateWrapper();
+ await wrapper.vm.$nextTick();
+ await flushPromises();
+ expect(htmlRemoveId(wrapper.html())).toMatchSnapshot();
+ expect(requestHandlers.handle_0).toHaveBeenCalledTimes(1);
+ });
+});
diff --git a/tests/unit/specs/components/Group/__snapshots__/CreateView.spec.ts.snap b/tests/unit/specs/components/Group/__snapshots__/CreateView.spec.ts.snap
new file mode 100644
index 000000000..dbb5ca5ff
--- /dev/null
+++ b/tests/unit/specs/components/Group/__snapshots__/CreateView.spec.ts.snap
@@ -0,0 +1,138 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`CreateView > Show simple 1`] = `
+"Create a new group
+
+
Groups are spaces for coordination and preparation to better organize events and manage your community.
+ +You are not part of any group. Do you wish to create a group or explore the groups?
++
+
+
+
+
+
+
+
+
+