diff --git a/app/soapbox/__fixtures__/group-truthsocial.json b/app/soapbox/__fixtures__/group-truthsocial.json
new file mode 100644
index 0000000000..f874f6892d
--- /dev/null
+++ b/app/soapbox/__fixtures__/group-truthsocial.json
@@ -0,0 +1,16 @@
+{
+ "note": "patriots 900000001",
+ "discoverable": true,
+ "id": "109989480368015378",
+ "domain": null,
+ "avatar": "https://media.covfefe.social/groups/avatars/109/989/480/368/015/378/original/50b0d899bc5aae13.jpg",
+ "avatar_static": "https://media.covfefe.social/groups/avatars/109/989/480/368/015/378/original/50b0d899bc5aae13.jpg",
+ "header": "https://media.covfefe.social/groups/headers/109/989/480/368/015/378/original/c5063b59f919cd4a.png",
+ "header_static": "https://media.covfefe.social/groups/headers/109/989/480/368/015/378/original/c5063b59f919cd4a.png",
+ "group_visibility": "everyone",
+ "created_at": "2023-03-08T00:00:00.000Z",
+ "display_name": "PATRIOT PATRIOTS",
+ "membership_required": true,
+ "members_count": 1,
+ "tags": []
+}
\ No newline at end of file
diff --git a/app/soapbox/features/group/components/__tests__/group-action-button.test.tsx b/app/soapbox/features/group/components/__tests__/group-action-button.test.tsx
index e622c72470..03f80fd9cf 100644
--- a/app/soapbox/features/group/components/__tests__/group-action-button.test.tsx
+++ b/app/soapbox/features/group/components/__tests__/group-action-button.test.tsx
@@ -1,7 +1,7 @@
import React from 'react';
+import { buildGroup, buildGroupRelationship } from 'soapbox/jest/factory';
import { render, screen } from 'soapbox/jest/test-helpers';
-import { normalizeGroup, normalizeGroupRelationship } from 'soapbox/normalizers';
import { Group } from 'soapbox/types/entities';
import GroupActionButton from '../group-action-button';
@@ -11,7 +11,7 @@ let group: Group;
describe('', () => {
describe('with no group relationship', () => {
beforeEach(() => {
- group = normalizeGroup({
+ group = buildGroup({
relationship: null,
});
});
@@ -43,8 +43,8 @@ describe('', () => {
describe('with no group relationship member', () => {
beforeEach(() => {
- group = normalizeGroup({
- relationship: normalizeGroupRelationship({
+ group = buildGroup({
+ relationship: buildGroupRelationship({
member: null,
}),
});
@@ -77,8 +77,8 @@ describe('', () => {
describe('when the user has requested to join', () => {
beforeEach(() => {
- group = normalizeGroup({
- relationship: normalizeGroupRelationship({
+ group = buildGroup({
+ relationship: buildGroupRelationship({
requested: true,
member: true,
}),
@@ -94,8 +94,8 @@ describe('', () => {
describe('when the user is an Admin', () => {
beforeEach(() => {
- group = normalizeGroup({
- relationship: normalizeGroupRelationship({
+ group = buildGroup({
+ relationship: buildGroupRelationship({
requested: false,
member: true,
role: 'admin',
@@ -112,8 +112,8 @@ describe('', () => {
describe('when the user is just a member', () => {
beforeEach(() => {
- group = normalizeGroup({
- relationship: normalizeGroupRelationship({
+ group = buildGroup({
+ relationship: buildGroupRelationship({
requested: false,
member: true,
role: 'user',
diff --git a/app/soapbox/features/group/components/__tests__/group-member-count.test.tsx b/app/soapbox/features/group/components/__tests__/group-member-count.test.tsx
index 9a26c27296..c6e31f8a8c 100644
--- a/app/soapbox/features/group/components/__tests__/group-member-count.test.tsx
+++ b/app/soapbox/features/group/components/__tests__/group-member-count.test.tsx
@@ -1,7 +1,7 @@
import React from 'react';
+import { buildGroup } from 'soapbox/jest/factory';
import { render, screen } from 'soapbox/jest/test-helpers';
-import { normalizeGroup } from 'soapbox/normalizers';
import { Group } from 'soapbox/types/entities';
import GroupMemberCount from '../group-member-count';
@@ -12,7 +12,7 @@ describe('', () => {
describe('with support for "members_count"', () => {
describe('with 1 member', () => {
beforeEach(() => {
- group = normalizeGroup({
+ group = buildGroup({
members_count: 1,
});
});
@@ -26,7 +26,7 @@ describe('', () => {
describe('with 2 members', () => {
beforeEach(() => {
- group = normalizeGroup({
+ group = buildGroup({
members_count: 2,
});
});
@@ -40,7 +40,7 @@ describe('', () => {
describe('with 1000 members', () => {
beforeEach(() => {
- group = normalizeGroup({
+ group = buildGroup({
members_count: 1000,
});
});
diff --git a/app/soapbox/features/group/components/__tests__/group-privacy.test.tsx b/app/soapbox/features/group/components/__tests__/group-privacy.test.tsx
index 72e4454e7a..3a2d4d9eba 100644
--- a/app/soapbox/features/group/components/__tests__/group-privacy.test.tsx
+++ b/app/soapbox/features/group/components/__tests__/group-privacy.test.tsx
@@ -1,7 +1,7 @@
import React from 'react';
+import { buildGroup } from 'soapbox/jest/factory';
import { render, screen } from 'soapbox/jest/test-helpers';
-import { normalizeGroup } from 'soapbox/normalizers';
import { Group } from 'soapbox/types/entities';
import GroupPrivacy from '../group-privacy';
@@ -11,7 +11,7 @@ let group: Group;
describe('', () => {
describe('with a Private group', () => {
beforeEach(() => {
- group = normalizeGroup({
+ group = buildGroup({
locked: true,
});
});
@@ -25,7 +25,7 @@ describe('', () => {
describe('with a Public group', () => {
beforeEach(() => {
- group = normalizeGroup({
+ group = buildGroup({
locked: false,
});
});
diff --git a/app/soapbox/features/groups/components/discover/search/__tests__/search.test.tsx b/app/soapbox/features/groups/components/discover/search/__tests__/search.test.tsx
index 698608363e..0c19eba01d 100644
--- a/app/soapbox/features/groups/components/discover/search/__tests__/search.test.tsx
+++ b/app/soapbox/features/groups/components/discover/search/__tests__/search.test.tsx
@@ -1,8 +1,9 @@
import React from 'react';
import { __stub } from 'soapbox/api';
+import { buildGroup } from 'soapbox/jest/factory';
import { render, screen, waitFor } from 'soapbox/jest/test-helpers';
-import { normalizeGroup, normalizeInstance } from 'soapbox/normalizers';
+import { normalizeInstance } from 'soapbox/normalizers';
import Search from '../search';
@@ -35,7 +36,7 @@ describe('', () => {
beforeEach(() => {
__stub((mock) => {
mock.onGet('/api/v1/groups/search').reply(200, [
- normalizeGroup({
+ buildGroup({
display_name: 'Group',
id: '1',
}),
diff --git a/app/soapbox/hooks/__tests__/useGroupsPath.test.ts b/app/soapbox/hooks/__tests__/useGroupsPath.test.ts
index c3ec1e169a..7596acd9a0 100644
--- a/app/soapbox/hooks/__tests__/useGroupsPath.test.ts
+++ b/app/soapbox/hooks/__tests__/useGroupsPath.test.ts
@@ -1,8 +1,9 @@
import { Map as ImmutableMap } from 'immutable';
import { __stub } from 'soapbox/api';
+import { buildGroup, buildGroupRelationship } from 'soapbox/jest/factory';
import { renderHook, waitFor } from 'soapbox/jest/test-helpers';
-import { normalizeAccount, normalizeGroup, normalizeGroupRelationship, normalizeInstance } from 'soapbox/normalizers';
+import { normalizeAccount, normalizeInstance } from 'soapbox/normalizers';
import { useGroupsPath } from '../useGroupsPath';
@@ -53,14 +54,14 @@ describe('useGroupsPath()', () => {
beforeEach(() => {
__stub((mock) => {
mock.onGet('/api/v1/groups').reply(200, [
- normalizeGroup({
+ buildGroup({
display_name: 'Group',
id: '1',
}),
]);
mock.onGet('/api/v1/groups/relationships?id[]=1').reply(200, [
- normalizeGroupRelationship({
+ buildGroupRelationship({
id: '1',
}),
]);
diff --git a/app/soapbox/jest/factory.ts b/app/soapbox/jest/factory.ts
new file mode 100644
index 0000000000..4f2eb145cc
--- /dev/null
+++ b/app/soapbox/jest/factory.ts
@@ -0,0 +1,20 @@
+import { v4 as uuidv4 } from 'uuid';
+
+import { groupSchema, Group, groupRelationshipSchema, GroupRelationship } from 'soapbox/schemas';
+
+// TODO: there's probably a better way to create these factory functions.
+// This looks promising but didn't work on my first attempt: https://github.com/anatine/zod-plugins/tree/main/packages/zod-mock
+
+function buildGroup(props: Record = {}): Group {
+ return groupSchema.parse(Object.assign({
+ id: uuidv4(),
+ }, props));
+}
+
+function buildGroupRelationship(props: Record = {}): GroupRelationship {
+ return groupRelationshipSchema.parse(Object.assign({
+ id: uuidv4(),
+ }, props));
+}
+
+export { buildGroup, buildGroupRelationship };
\ No newline at end of file
diff --git a/app/soapbox/schemas/__tests__/group.test.ts b/app/soapbox/schemas/__tests__/group.test.ts
new file mode 100644
index 0000000000..9cdfb66d91
--- /dev/null
+++ b/app/soapbox/schemas/__tests__/group.test.ts
@@ -0,0 +1,7 @@
+import { groupSchema } from '../group';
+
+test('groupSchema with a TruthSocial group', () => {
+ const data = require('soapbox/__fixtures__/group-truthsocial.json');
+ const group = groupSchema.parse(data);
+ expect(group.display_name_html).toEqual('PATRIOT PATRIOTS');
+});
\ No newline at end of file
diff --git a/app/soapbox/schemas/group.ts b/app/soapbox/schemas/group.ts
index 6a8f03c8f1..48e3e77afc 100644
--- a/app/soapbox/schemas/group.ts
+++ b/app/soapbox/schemas/group.ts
@@ -21,7 +21,7 @@ const groupSchema = z.object({
group_visibility: z.string().catch(''), // TruthSocial
header: z.string().catch(headerMissing),
header_static: z.string().catch(''),
- id: z.string().catch(''),
+ id: z.string(),
locked: z.boolean().catch(false),
membership_required: z.boolean().catch(false),
members_count: z.number().catch(0),