| 
 | 1 | +/**  | 
 | 2 | + * WordPress dependencies  | 
 | 3 | + */  | 
 | 4 | +import { test, expect } from '@wordpress/e2e-test-utils-playwright';  | 
 | 5 | + | 
 | 6 | +test.describe( 'ActivityPub Following Collection REST API', () => {  | 
 | 7 | +	let testUserId;  | 
 | 8 | +	let followingEndpoint;  | 
 | 9 | + | 
 | 10 | +	test.beforeAll( async ( { requestUtils } ) => {  | 
 | 11 | +		// Use the default test user  | 
 | 12 | +		testUserId = 1;  | 
 | 13 | +		followingEndpoint = `/activitypub/1.0/users/${ testUserId }/following`;  | 
 | 14 | +	} );  | 
 | 15 | + | 
 | 16 | +	test( 'should return 200 status code for following endpoint', async ( { requestUtils } ) => {  | 
 | 17 | +		const data = await requestUtils.rest( {  | 
 | 18 | +			path: followingEndpoint,  | 
 | 19 | +		} );  | 
 | 20 | + | 
 | 21 | +		expect( data ).toBeDefined();  | 
 | 22 | +	} );  | 
 | 23 | + | 
 | 24 | +	test( 'should return ActivityStreams OrderedCollection', async ( { requestUtils } ) => {  | 
 | 25 | +		const data = await requestUtils.rest( {  | 
 | 26 | +			path: followingEndpoint,  | 
 | 27 | +		} );  | 
 | 28 | + | 
 | 29 | +		// Check for ActivityStreams context  | 
 | 30 | +		expect( data ).toHaveProperty( '@context' );  | 
 | 31 | +		expect( Array.isArray( data[ '@context' ] ) || typeof data[ '@context' ] === 'string' ).toBe( true );  | 
 | 32 | + | 
 | 33 | +		// Verify it's an OrderedCollection  | 
 | 34 | +		expect( data.type ).toBe( 'OrderedCollection' );  | 
 | 35 | + | 
 | 36 | +		// Check for required collection properties  | 
 | 37 | +		expect( data ).toHaveProperty( 'id' );  | 
 | 38 | +		expect( data.id ).toMatch( /^https?:\/\// );  | 
 | 39 | + | 
 | 40 | +		expect( data ).toHaveProperty( 'totalItems' );  | 
 | 41 | +		expect( typeof data.totalItems ).toBe( 'number' );  | 
 | 42 | +	} );  | 
 | 43 | + | 
 | 44 | +	test( 'should handle empty following collection', async ( { requestUtils } ) => {  | 
 | 45 | +		const data = await requestUtils.rest( {  | 
 | 46 | +			path: followingEndpoint,  | 
 | 47 | +		} );  | 
 | 48 | + | 
 | 49 | +		// For a new user, following should be 0  | 
 | 50 | +		if ( data.totalItems === 0 ) {  | 
 | 51 | +			expect( data.orderedItems ).toEqual( [] );  | 
 | 52 | +		}  | 
 | 53 | +	} );  | 
 | 54 | + | 
 | 55 | +	test( 'should include first property for pagination', async ( { requestUtils } ) => {  | 
 | 56 | +		const data = await requestUtils.rest( {  | 
 | 57 | +			path: followingEndpoint,  | 
 | 58 | +		} );  | 
 | 59 | + | 
 | 60 | +		if ( data.totalItems > 0 ) {  | 
 | 61 | +			expect( data ).toHaveProperty( 'first' );  | 
 | 62 | + | 
 | 63 | +			if ( typeof data.first === 'string' ) {  | 
 | 64 | +				expect( data.first ).toMatch( /^https?:\/\// );  | 
 | 65 | +			} else if ( typeof data.first === 'object' ) {  | 
 | 66 | +				expect( data.first.type ).toBe( 'OrderedCollectionPage' );  | 
 | 67 | +				expect( data.first ).toHaveProperty( 'orderedItems' );  | 
 | 68 | +			}  | 
 | 69 | +		}  | 
 | 70 | +	} );  | 
 | 71 | + | 
 | 72 | +	test( 'should return error for non-existent user', async ( { requestUtils } ) => {  | 
 | 73 | +		try {  | 
 | 74 | +			await requestUtils.rest( {  | 
 | 75 | +				path: '/activitypub/1.0/users/999999/following',  | 
 | 76 | +			} );  | 
 | 77 | +			// If we reach here, the test should fail  | 
 | 78 | +			expect.fail();  | 
 | 79 | +		} catch ( error ) {  | 
 | 80 | +			// Should return 400 or 404 for invalid/non-existent user  | 
 | 81 | +			expect( [ 400, 404 ] ).toContain( error.status || error.code );  | 
 | 82 | +		}  | 
 | 83 | +	} );  | 
 | 84 | + | 
 | 85 | +	test( 'should return correct Content-Type header', async ( { requestUtils } ) => {  | 
 | 86 | +		const data = await requestUtils.rest( {  | 
 | 87 | +			path: followingEndpoint,  | 
 | 88 | +		} );  | 
 | 89 | + | 
 | 90 | +		expect( data ).toBeDefined();  | 
 | 91 | +		expect( data ).toHaveProperty( 'type' );  | 
 | 92 | +	} );  | 
 | 93 | + | 
 | 94 | +	test( 'should handle page parameter', async ( { requestUtils } ) => {  | 
 | 95 | +		try {  | 
 | 96 | +			const data = await requestUtils.rest( {  | 
 | 97 | +				path: `${ followingEndpoint }?page=1`,  | 
 | 98 | +			} );  | 
 | 99 | + | 
 | 100 | +			// If successful, verify the response structure  | 
 | 101 | +			expect( data.type ).toBe( 'OrderedCollectionPage' );  | 
 | 102 | +		} catch ( error ) {  | 
 | 103 | +			// Skip this test if pagination isn't available yet  | 
 | 104 | +			expect( error.status || error.code ).toBeGreaterThanOrEqual( 400 );  | 
 | 105 | +		}  | 
 | 106 | +	} );  | 
 | 107 | + | 
 | 108 | +	test( 'should validate collection structure matches ActivityStreams spec', async ( { requestUtils } ) => {  | 
 | 109 | +		const data = await requestUtils.rest( {  | 
 | 110 | +			path: followingEndpoint,  | 
 | 111 | +		} );  | 
 | 112 | + | 
 | 113 | +		// Check for required ActivityStreams properties  | 
 | 114 | +		expect( data ).toHaveProperty( '@context' );  | 
 | 115 | +		expect( Array.isArray( data[ '@context' ] ) || typeof data[ '@context' ] === 'string' ).toBe( true );  | 
 | 116 | + | 
 | 117 | +		// Verify ID is a valid URL  | 
 | 118 | +		expect( data.id ).toMatch( /^https?:\/\// );  | 
 | 119 | + | 
 | 120 | +		// Verify proper typing  | 
 | 121 | +		expect( data.type ).toBe( 'OrderedCollection' );  | 
 | 122 | +	} );  | 
 | 123 | + | 
 | 124 | +	test( 'should validate orderedItems structure when present', async ( { requestUtils } ) => {  | 
 | 125 | +		const data = await requestUtils.rest( {  | 
 | 126 | +			path: followingEndpoint,  | 
 | 127 | +		} );  | 
 | 128 | + | 
 | 129 | +		if ( data.orderedItems && data.orderedItems.length > 0 ) {  | 
 | 130 | +			// Each item should be either a URL string or an object  | 
 | 131 | +			data.orderedItems.forEach( ( item ) => {  | 
 | 132 | +				if ( typeof item === 'string' ) {  | 
 | 133 | +					expect( item ).toMatch( /^https?:\/\// );  | 
 | 134 | +				} else if ( typeof item === 'object' ) {  | 
 | 135 | +					expect( item ).toHaveProperty( 'type' );  | 
 | 136 | +					expect( item ).toHaveProperty( 'id' );  | 
 | 137 | +				}  | 
 | 138 | +			} );  | 
 | 139 | +		}  | 
 | 140 | +	} );  | 
 | 141 | +} );  | 
0 commit comments