返回 AiToEarn
publish-content.utils.spec.ts
根目录 / project / aitoearn-backend / apps / aitoearn-server / src / core / channels / utils / publish-content.utils.spec.ts
1 import { describe, expect, it } from 'vitest'
2 import { PublishContentMode } from '../platforms/platforms.interface'
3 import { PublishValidationCombination, PublishValidationField, PublishValidationIssueCode } from '../platforms/publish.schema'
4 import { validatePublishContent } from './publish-content.utils'
5
6 describe('validatePublishContent modes', () => {
7 it('rejects unsupported text mode', () => {
8 const issues = validatePublishContent(
9 { title: 'title', body: 'body', media: [] },
10 { modes: [PublishContentMode.Video] },
11 )
12
13 expect(issues).toContainEqual(expect.objectContaining({
14 code: PublishValidationIssueCode.UnsupportedContentMode,
15 params: expect.objectContaining({ mode: PublishContentMode.Text }),
16 }))
17 })
18
19 it('rejects unsupported image-text mode', () => {
20 const issues = validatePublishContent(
21 { body: 'body', media: [{ url: 'https://assets.example.test/a.jpg' }] },
22 { modes: [PublishContentMode.Video] },
23 )
24
25 expect(issues).toContainEqual(expect.objectContaining({
26 code: PublishValidationIssueCode.UnsupportedContentMode,
27 params: expect.objectContaining({ mode: PublishContentMode.ImageText }),
28 }))
29 })
30
31 it('rejects unsupported video mode', () => {
32 const issues = validatePublishContent(
33 { body: 'body', media: [{ url: 'https://assets.example.test/a.mp4' }] },
34 { modes: [PublishContentMode.ImageText] },
35 )
36
37 expect(issues).toContainEqual(expect.objectContaining({
38 code: PublishValidationIssueCode.UnsupportedContentMode,
39 params: expect.objectContaining({ mode: PublishContentMode.Video }),
40 }))
41 })
42
43 it('allows declared content modes', () => {
44 const limits = {
45 modes: [PublishContentMode.Text, PublishContentMode.ImageText, PublishContentMode.Video],
46 }
47
48 expect(validatePublishContent({ body: 'body', media: [] }, limits)).toEqual([])
49 expect(validatePublishContent({
50 body: 'body',
51 media: [],
52 cover: { url: 'https://assets.example.test/cover.jpg' },
53 }, limits)).toEqual([])
54 expect(validatePublishContent({ body: 'body', media: [{ url: 'https://assets.example.test/a.jpg' }] }, limits)).toEqual([])
55 expect(validatePublishContent({ body: 'body', media: [{ url: 'https://assets.example.test/a.mp4' }] }, limits)).toEqual([])
56 })
57
58 it('treats text with cover as image-text mode', () => {
59 const issues = validatePublishContent(
60 {
61 body: 'body',
62 media: [],
63 cover: { url: 'https://assets.example.test/cover.jpg' },
64 },
65 { modes: [PublishContentMode.Text] },
66 )
67
68 expect(issues).toContainEqual(expect.objectContaining({
69 code: PublishValidationIssueCode.UnsupportedContentMode,
70 params: expect.objectContaining({ mode: PublishContentMode.ImageText }),
71 }))
72 })
73
74 it('keeps mixed image/video as invalid combination instead of unsupported mode', () => {
75 const issues = validatePublishContent(
76 {
77 body: 'body',
78 media: [
79 { url: 'https://assets.example.test/a.jpg' },
80 { url: 'https://assets.example.test/a.mp4' },
81 ],
82 },
83 { modes: [PublishContentMode.ImageText, PublishContentMode.Video] },
84 )
85
86 expect(issues).toContainEqual(expect.objectContaining({
87 code: PublishValidationIssueCode.InvalidCombination,
88 params: expect.objectContaining({ combination: PublishValidationCombination.ImageVideo }),
89 }))
90 expect(issues).not.toContainEqual(expect.objectContaining({
91 code: PublishValidationIssueCode.UnsupportedContentMode,
92 }))
93 })
94
95 it('classifies media by URL path extension instead of query string substrings', () => {
96 const issues = validatePublishContent(
97 {
98 body: 'body',
99 media: [{ url: 'https://assets.example.test/image.jpg?format=mp4' }],
100 },
101 { modes: [PublishContentMode.ImageText] },
102 )
103
104 expect(issues).toEqual([])
105 })
106
107 it('classifies signed URL media by server metadata type before URL extension fallback', () => {
108 const issues = validatePublishContent(
109 {
110 body: 'body',
111 media: [{ url: 'https://assets.example.test/download?id=video-1', metadata: { type: 'video' } }],
112 },
113 { modes: [PublishContentMode.Video] },
114 )
115
116 expect(issues).toEqual([])
117 })
118
119 it('detects image and video combinations from server metadata type', () => {
120 const issues = validatePublishContent(
121 {
122 body: 'body',
123 media: [
124 { url: 'https://assets.example.test/download?id=image-1', metadata: { type: 'image' } },
125 { url: 'https://assets.example.test/download?id=video-1', metadata: { type: 'video' } },
126 ],
127 },
128 { modes: [PublishContentMode.ImageText, PublishContentMode.Video] },
129 )
130
131 expect(issues).toContainEqual(expect.objectContaining({
132 code: PublishValidationIssueCode.InvalidCombination,
133 params: expect.objectContaining({ combination: PublishValidationCombination.ImageVideo }),
134 }))
135 expect(issues).not.toContainEqual(expect.objectContaining({
136 code: PublishValidationIssueCode.UnsupportedContentMode,
137 }))
138 })
139
140 it('accepts extensionless covers when server metadata classifies them as images', () => {
141 const issues = validatePublishContent(
142 {
143 body: 'body',
144 media: [],
145 cover: {
146 url: 'https://assets.example.test/download?id=cover-1',
147 metadata: { type: 'image' },
148 },
149 },
150 { modes: [PublishContentMode.ImageText] },
151 )
152
153 expect(issues).toEqual([])
154 })
155
156 it('rejects topics parsed from body when platform topic maxCount is exceeded', () => {
157 const issues = validatePublishContent(
158 {
159 body: '#a #b #c #d #e #f',
160 media: [],
161 },
162 { modes: [PublishContentMode.Text] },
163 { supported: true, maxCount: 5 },
164 )
165
166 expect(issues).toContainEqual(expect.objectContaining({
167 code: PublishValidationIssueCode.TooBig,
168 path: ['content', 'topics'],
169 params: expect.objectContaining({
170 field: PublishValidationField.Topic,
171 maximum: 5,
172 }),
173 }))
174 })
175
176 it('uses stripped body length for platforms with native topic fields', () => {
177 expect(validatePublishContent(
178 {
179 body: '正文 #很长很长的话题',
180 media: [],
181 },
182 { modes: [PublishContentMode.Text], maxBodyLength: 2 },
183 { supported: true, nativeField: true },
184 )).toEqual([])
185
186 expect(validatePublishContent(
187 {
188 title: '标题',
189 body: '#话题',
190 media: [],
191 },
192 { modes: [PublishContentMode.Text], maxTotalTextLength: 2 },
193 { supported: true, nativeField: true },
194 )).toEqual([])
195 })
196 })
197
197 lines TYPESCRIPT