Commit 0502a811df9 for woocommerce

commit 0502a811df9f3c1792c09080c4eb943dc3537708
Author: Adrian Moldovan <3854374+adimoldovan@users.noreply.github.com>
Date:   Thu Jun 18 19:31:23 2026 +0200

    [e2e tests]: Replace dead demo.woothemes.com image URLs with local media (#65840)

diff --git a/plugins/woocommerce/changelog/fix-e2e-replace-dead-demo-image-urls b/plugins/woocommerce/changelog/fix-e2e-replace-dead-demo-image-urls
new file mode 100644
index 00000000000..905c86474f9
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-e2e-replace-dead-demo-image-urls
@@ -0,0 +1,3 @@
+Significance: patch
+Type: dev
+Comment: E2E test-only change. Replace dead demo.woothemes.com image URLs with local media library lookups. No user-facing change.
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/api-tests/orders/orders.test.ts b/plugins/woocommerce/tests/e2e-pw/tests/api-tests/orders/orders.test.ts
index 7c7bd500ecc..3d6c059b44b 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/api-tests/orders/orders.test.ts
+++ b/plugins/woocommerce/tests/e2e-pw/tests/api-tests/orders/orders.test.ts
@@ -8,6 +8,7 @@ import { faker } from '@faker-js/faker';
  */
 import { test, expect } from '../../../fixtures/api-tests-fixtures';
 import { order } from '../../../data';
+import { getMediaBySlug } from '../../../utils/media';

 const RAND_STRING = faker.string.alphanumeric( 8 ).toLowerCase();
 const COUPON_CODE = `coupon-${ faker.string.alphanumeric( 4 ).toLowerCase() }`;
@@ -234,6 +235,13 @@ test.describe.serial( 'Orders API tests', () => {
 				'Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. ' +
 				'Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>\n';

+			const { source_url: downloadFile } = await getMediaBySlug(
+				'image-01'
+			);
+			const { source_url: downloadFile2 } = await getMediaBySlug(
+				'image-02'
+			);
+
 			const simpleProducts = await request.post(
 				'./wp-json/wc/v3/products/batch',
 				{
@@ -407,7 +415,7 @@ test.describe.serial( 'Orders API tests', () => {
 									{
 										id: '2579cf07-8b08-4c25-888a-b6258dd1f035',
 										name: 'Single',
-										file: 'https://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2017/08/single.jpg',
+										file: downloadFile,
 									},
 								],
 								download_limit: 1,
@@ -477,12 +485,12 @@ test.describe.serial( 'Orders API tests', () => {
 									{
 										id: 'cc10249f-1de2-44d4-93d3-9f88ae629f76',
 										name: 'Single 1',
-										file: 'https://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2017/08/single.jpg',
+										file: downloadFile,
 									},
 									{
 										id: 'aea8ef69-ccdc-4d83-8e21-3c395ebb9411',
 										name: 'Single 2',
-										file: 'https://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2017/08/album.jpg',
+										file: downloadFile2,
 									},
 								],
 								download_limit: 1,
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/api-tests/products/product-list.test.ts b/plugins/woocommerce/tests/e2e-pw/tests/api-tests/products/product-list.test.ts
index 020c5524c5f..330974b0ee2 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/api-tests/products/product-list.test.ts
+++ b/plugins/woocommerce/tests/e2e-pw/tests/api-tests/products/product-list.test.ts
@@ -7,6 +7,7 @@ import { faker } from '@faker-js/faker';
  * Internal dependencies
  */
 import { test, expect } from '../../../fixtures/api-tests-fixtures';
+import { getMediaBySlug } from '../../../utils/media';

 test.describe( 'Products API tests: List All Products', () => {
 	const PRODUCTS_COUNT = 20;
@@ -214,6 +215,13 @@ test.describe( 'Products API tests: List All Products', () => {
 				'Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. ' +
 				'Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>\n';

+			const { source_url: downloadFile } = await getMediaBySlug(
+				'image-01'
+			);
+			const { source_url: downloadFile2 } = await getMediaBySlug(
+				'image-02'
+			);
+
 			//const { body: simpleProducts } = await createProducts( [
 			const simpleProducts = await request.post(
 				'./wp-json/wc/v3/products/batch',
@@ -391,7 +399,7 @@ test.describe( 'Products API tests: List All Products', () => {
 									{
 										id: '2579cf07-8b08-4c25-888a-b6258dd1f035',
 										name: 'Single',
-										file: 'https://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2017/08/single.jpg',
+										file: downloadFile,
 									},
 								],
 								download_limit: 1,
@@ -462,12 +470,12 @@ test.describe( 'Products API tests: List All Products', () => {
 									{
 										id: 'cc10249f-1de2-44d4-93d3-9f88ae629f76',
 										name: 'Single 1',
-										file: 'https://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2017/08/single.jpg',
+										file: downloadFile,
 									},
 									{
 										id: 'aea8ef69-ccdc-4d83-8e21-3c395ebb9411',
 										name: 'Single 2',
-										file: 'https://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2017/08/album.jpg',
+										file: downloadFile2,
 									},
 								],
 								download_limit: 1,
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/order/order-edit.spec.ts b/plugins/woocommerce/tests/e2e-pw/tests/order/order-edit.spec.ts
index a485af0204a..a737f55a378 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/order/order-edit.spec.ts
+++ b/plugins/woocommerce/tests/e2e-pw/tests/order/order-edit.spec.ts
@@ -9,6 +9,7 @@ import { ApiClient, WC_API_PATH } from '@woocommerce/e2e-utils-playwright';
 import { tags, expect, test } from '../../fixtures/fixtures';
 import { ADMIN_STATE_PATH } from '../../playwright.config';
 import { random } from '../../utils/helpers';
+import { getMediaBySlug } from '../../utils/media';

 test.use( { storageState: ADMIN_STATE_PATH } );

@@ -394,7 +395,8 @@ test.describe(
 			productId: number,
 			product2Id: number,
 			noProductOrderId: number,
-			initialGrantAccessAfterPaymentSetting: string;
+			initialGrantAccessAfterPaymentSetting: string,
+			downloadFile: string;

 		/**
 		 * Enable the "Grant access to downloadable products after payment" setting in WooCommerce > Settings > Products > Downloadable products.
@@ -426,6 +428,10 @@ test.describe(
 			} );
 		};

+		test.beforeAll( async () => {
+			( { source_url: downloadFile } = await getMediaBySlug( 'image-01' ) );
+		} );
+
 		test.beforeEach( async ( { restApi } ) => {
 			await restApi
 				.post( `${ WC_API_PATH }/products`, {
@@ -436,7 +442,7 @@ test.describe(
 						{
 							id: random(),
 							name: 'Single',
-							file: 'https://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2017/08/single.jpg',
+							file: downloadFile,
 						},
 					],
 				} )
@@ -455,7 +461,7 @@ test.describe(
 						{
 							id: random(),
 							name: 'Single',
-							file: 'https://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2017/08/single.jpg',
+							file: downloadFile,
 						},
 					],
 				} )
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/product/product-images.spec.ts b/plugins/woocommerce/tests/e2e-pw/tests/product/product-images.spec.ts
index 051e89e79be..d3fa825ed42 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/product/product-images.spec.ts
+++ b/plugins/woocommerce/tests/e2e-pw/tests/product/product-images.spec.ts
@@ -9,6 +9,7 @@ import type { Page } from '@playwright/test';
  */
 import { test as baseTest, expect } from '../../fixtures/fixtures';
 import { ADMIN_STATE_PATH } from '../../playwright.config';
+import { getMediaBySlug } from '../../utils/media';

 async function addImageFromLibrary(
 	page: Page,
@@ -50,14 +51,11 @@ const test = baseTest.extend( {
 		} );
 	},
 	productWithImage: async ( { restApi, product }, use ) => {
+		const { id: imageId } = await getMediaBySlug( 'image-01' );
 		let productWithImage;
 		await restApi
 			.put( `${ WC_API_PATH }/products/${ product.id }`, {
-				images: [
-					{
-						src: 'http://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2013/06/T_2_front.jpg',
-					},
-				],
+				images: [ { id: imageId } ],
 			} )
 			.then( ( response ) => {
 				productWithImage = response.data;
@@ -66,20 +64,15 @@ const test = baseTest.extend( {
 		await use( productWithImage );
 	},
 	productWithGallery: async ( { restApi, product }, use ) => {
+		const imageIds = await Promise.all(
+			[ 'image-01', 'image-02', 'image-03' ].map(
+				async ( slug ) => ( await getMediaBySlug( slug ) ).id
+			)
+		);
 		let productWithGallery;
 		await restApi
 			.put( `${ WC_API_PATH }/products/${ product.id }`, {
-				images: [
-					{
-						src: 'http://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2013/06/T_2_front.jpg',
-					},
-					{
-						src: 'http://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2013/06/T_2_back.jpg',
-					},
-					{
-						src: 'http://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2013/06/T_3_front.jpg',
-					},
-				],
+				images: imageIds.map( ( id ) => ( { id } ) ),
 			} )
 			.then( ( response ) => {
 				productWithGallery = response.data;
diff --git a/plugins/woocommerce/tests/e2e-pw/utils/media.ts b/plugins/woocommerce/tests/e2e-pw/utils/media.ts
new file mode 100644
index 00000000000..da2ba0c4de7
--- /dev/null
+++ b/plugins/woocommerce/tests/e2e-pw/utils/media.ts
@@ -0,0 +1,54 @@
+/**
+ * External dependencies
+ */
+import { createClient } from '@woocommerce/e2e-utils-playwright';
+
+/**
+ * Internal dependencies
+ */
+import { admin } from '../test-data/data';
+import playwrightConfig from '../playwright.config';
+
+let api: ReturnType< typeof createClient > | null = null;
+
+function getApi() {
+	if ( ! api ) {
+		api = createClient( playwrightConfig.use.baseURL, {
+			type: 'basic',
+			username: admin.username,
+			password: admin.password,
+		} );
+	}
+	return api;
+}
+
+const cache = new Map< string, { id: number; source_url: string } >();
+
+/**
+ * Resolve a media library item by its slug.
+ *
+ * The `image-01/02/03` images are imported into the media library during site
+ * setup (see `bin/test-env-setup.sh`). Returns the attachment so callers can use
+ * its `id` (e.g. product images) or `source_url` (e.g. downloadable files, which
+ * must live within the approved uploads directory) instead of relying on an
+ * external URL.
+ *
+ * @param {string} slug The attachment slug, e.g. `image-01`.
+ * @return The resolved attachment with `id` and `source_url`.
+ */
+export const getMediaBySlug = async (
+	slug: string
+): Promise< { id: number; source_url: string } > => {
+	if ( cache.has( slug ) ) {
+		return cache.get( slug )!;
+	}
+	const response = await getApi().get<
+		Array< { id: number; source_url: string } >
+	>( 'wp/v2/media', { slug, per_page: 1 } );
+	const media = response.data?.[ 0 ];
+	if ( ! media ) {
+		throw new Error( `Media library image not found: ${ slug }` );
+	}
+	cache.set( slug, media );
+	return media;
+};