11import 'CourseAuthoring/editors/setupEditorTest' ;
22import { getConfig } from '@edx/frontend-platform' ;
3+ import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth' ;
4+ import * as keyUtils from '../../../generic/key-utils' ;
35import { MockUseState } from '../../testUtils' ;
46
57import * as tinyMCE from '../../data/constants/tinyMCE' ;
@@ -19,6 +21,10 @@ jest.mock('react', () => ({
1921 useCallback : ( cb , prereqs ) => ( { cb, prereqs } ) ,
2022} ) ) ;
2123
24+ jest . mock ( '@edx/frontend-platform/auth' , ( ) => ( {
25+ getAuthenticatedHttpClient : jest . fn ( ) ,
26+ } ) ) ;
27+
2228const state = new MockUseState ( module ) ;
2329const moduleKeys = keyStore ( module ) ;
2430
@@ -192,30 +198,34 @@ describe('TinyMceEditor hooks', () => {
192198 const initialContent = `<img src="/static/soMEImagEURl1.jpeg"/><a href="/assets/v1/${ baseAssetUrl } /test.pdf">test</a><img src="/${ baseAssetUrl } @correct.png" /><img src="/${ baseAssetUrl } /correct.png" />` ;
193199 const learningContextId = 'course-v1:org+test+run' ;
194200 const lmsEndpointUrl = getConfig ( ) . LMS_BASE_URL ;
195- it ( 'returns updated src for text editor to update content' , ( ) => {
201+
202+ beforeEach ( ( ) => {
203+ jest . clearAllMocks ( ) ;
204+ } ) ;
205+
206+ it ( 'returns updated src for text editor to update content' , async ( ) => {
196207 const expected = `<img src="/${ baseAssetUrl } @soMEImagEURl1.jpeg"/><a href="/${ baseAssetUrl } @test.pdf">test</a><img src="/${ baseAssetUrl } @correct.png" /><img src="/${ baseAssetUrl } @correct.png" />` ;
197- const actual = module . replaceStaticWithAsset ( {
208+ const actual = await module . replaceStaticWithAsset ( {
198209 initialContent,
199210 learningContextId,
200211 validateAssetUrl : false ,
201212 } ) ;
202213 expect ( actual ) . toEqual ( expected ) ;
203214 } ) ;
204- it ( 'returns updated src with absolute url for expandable editor to update content' , ( ) => {
205- const editorType = 'expandable' ;
215+ it ( 'returns updated src with absolute url for expandable editor to update content' , async ( ) => {
206216 const expected = `<img src="${ lmsEndpointUrl } /${ baseAssetUrl } @soMEImagEURl1.jpeg"/><a href="${ lmsEndpointUrl } /${ baseAssetUrl } @test.pdf">test</a><img src="${ lmsEndpointUrl } /${ baseAssetUrl } @correct.png" /><img src="${ lmsEndpointUrl } /${ baseAssetUrl } @correct.png" />` ;
207- const actual = module . replaceStaticWithAsset ( {
217+ const actual = await module . replaceStaticWithAsset ( {
208218 initialContent,
209- editorType,
219+ editorType : 'expandable' ,
210220 lmsEndpointUrl,
211221 learningContextId,
212222 validateAssetUrl : false ,
213223 } ) ;
214224 expect ( actual ) . toEqual ( expected ) ;
215225 } ) ;
216- it ( 'returns false when there are no srcs to update' , ( ) => {
226+ it ( 'returns false when there are no srcs to update' , async ( ) => {
217227 const content = '<div>Hello world!</div>' ;
218- const actual = module . replaceStaticWithAsset ( { initialContent : content , learningContextId } ) ;
228+ const actual = await module . replaceStaticWithAsset ( { initialContent : content , learningContextId } ) ;
219229 expect ( actual ) . toBeFalsy ( ) ;
220230 } ) ;
221231 it ( 'does not convert static URLs with subdirectories but converts direct static files' , ( ) => {
@@ -227,6 +237,79 @@ describe('TinyMceEditor hooks', () => {
227237 } ) ;
228238 expect ( actual ) . toEqual ( expected ) ;
229239 } ) ;
240+
241+ it ( 'replaces multiple static assets in one content string' , async ( ) => {
242+ const content = `
243+ <img src="/static/a.png"/>
244+ <img src="/static/b.png"/>
245+ ` ;
246+
247+ const result = await module . replaceStaticWithAsset ( {
248+ initialContent : content ,
249+ learningContextId,
250+ validateAssetUrl : false ,
251+ } ) ;
252+
253+ expect ( result ) . toBeTruthy ( ) ;
254+ } ) ;
255+
256+ it ( 'validateAssetUrl success path replaces url' , async ( ) => {
257+ getAuthenticatedHttpClient . mockReturnValue ( {
258+ get : jest . fn ( ( ) => Promise . resolve ( { } ) ) ,
259+ } ) ;
260+
261+ const content = '<img src="/static/test.png"/>' ;
262+
263+ const result = await module . replaceStaticWithAsset ( {
264+ initialContent : content ,
265+ learningContextId,
266+ validateAssetUrl : true ,
267+ } ) ;
268+
269+ expect ( result ) . toBeTruthy ( ) ;
270+ } ) ;
271+
272+ it ( 'validateAssetUrl failure path keeps original content' , async ( ) => {
273+ getAuthenticatedHttpClient . mockReturnValue ( {
274+ get : jest . fn ( ( ) => Promise . reject ( new Error ( '404' ) ) ) ,
275+ } ) ;
276+
277+ const content = '<img src="/static/test.png"/>' ;
278+
279+ const result = await module . replaceStaticWithAsset ( {
280+ initialContent : content ,
281+ learningContextId,
282+ validateAssetUrl : true ,
283+ } ) ;
284+
285+ expect ( result ) . toBeFalsy ( ) ;
286+ } ) ;
287+
288+ it ( 'handles library keys correctly' , async ( ) => {
289+ jest . spyOn ( keyUtils , 'isLibraryKey' ) . mockReturnValue ( true ) ;
290+
291+ const content = '<img src="/static/test.png"/>' ;
292+
293+ const result = await module . replaceStaticWithAsset ( {
294+ initialContent : content ,
295+ learningContextId : 'lib:test' ,
296+ validateAssetUrl : false ,
297+ } ) ;
298+
299+ expect ( result ) . toContain ( 'static/test.png' ) ;
300+ } ) ;
301+
302+ it ( 'returns false when asset already valid and no replacement needed' , async ( ) => {
303+ const content = '<img src="/asset-v1:test+org+run+type@[email protected] "/>' ; 304+
305+ const result = await module . replaceStaticWithAsset ( {
306+ initialContent : content ,
307+ learningContextId,
308+ validateAssetUrl : false ,
309+ } ) ;
310+
311+ expect ( result ) . toBe ( false ) ;
312+ } ) ;
230313 } ) ;
231314 describe ( 'setAssetToStaticUrl' , ( ) => {
232315 it ( 'returns content with updated img links' , ( ) => {
0 commit comments