Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions src/js/media/models/attachment.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,14 @@ Attachment = Backbone.Model.extend(/** @lends wp.media.model.Attachment.prototyp
} else if ( 'delete' === method ) {
options = options || {};

if ( ! options.wait ) {
this.destroyed = true;
}
/*
* Mark as destroyed before the request so mirrored collections
* filter it out when the `destroy` event fires. With `wait: true`,
* Backbone triggers `destroy` before the request's `done` handler,
* so setting the flag there was too late and the deleted item
* lingered in the grid. Restored on failure. See #65513.
*/
this.destroyed = true;

options.context = this;
options.data = _.extend( options.data || {}, {
Expand All @@ -82,9 +87,7 @@ Attachment = Backbone.Model.extend(/** @lends wp.media.model.Attachment.prototyp
_wpnonce: this.get('nonces')['delete']
});

return wp.media.ajax( options ).done( function() {
this.destroyed = true;
}).fail( function() {
return wp.media.ajax( options ).fail( function() {
this.destroyed = false;
});

Expand Down
17 changes: 13 additions & 4 deletions src/js/media/models/attachments.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,17 +204,26 @@ var Attachments = Backbone.Collection.extend(/** @lends wp.media.model.Attachmen
* Start observing another attachments collection change events
* and replicate them on this collection.
*
* @param {wp.media.model.Attachments} The attachments collection to observe.
* @param {wp.media.model.Attachments} attachments The attachments collection to observe.
* @return {wp.media.model.Attachments} Returns itself to allow chaining.
*/
observe: function( attachments ) {
this.observers = this.observers || [];
this.observers.push( attachments );

attachments.on( 'add change remove', this._validateHandler, this );
attachments.on( 'add', this._addToTotalAttachments, this );
attachments.on( 'remove', this._removeFromTotalAttachments, this );
attachments.on( 'reset', this._validateAllHandler, this );

/*
* Only count the mirrored query collection. Counting other observed
* collections such as the selection double-counts an uploaded image
* that is also auto-selected, breaking the count. See #65513.
*/
if ( attachments === this.mirroring ) {
attachments.on( 'add', this._addToTotalAttachments, this );
attachments.on( 'remove', this._removeFromTotalAttachments, this );
}

this.validateAll( attachments );
return this;
},
Expand All @@ -239,7 +248,7 @@ var Attachments = Backbone.Collection.extend(/** @lends wp.media.model.Attachmen
return this;
},
/**
* Update total attachment count when items are added to a collection.
* Update total attachment count when items are removed from a collection.
*
* @access private
*
Expand Down
79 changes: 79 additions & 0 deletions tests/e2e/specs/featured-image-modal.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/**
* WordPress dependencies
*/
import { test, expect } from '@wordpress/e2e-test-utils-playwright';

/**
* External dependencies
*/
import path from 'path';

const TEST_IMAGE = path.join(
__dirname,
'..',
'..',
'phpunit',
'data',
'images',
'test-image-1-100x100.jpg'
);

/**
* @see https://core.trac.wordpress.org/ticket/65513
*/
test.describe( 'Featured image modal media count and deletion', () => {
test.beforeEach( async ( { requestUtils } ) => {
// Start from an empty Media Library so the count is deterministic.
await requestUtils.deleteAllMedia();
} );

test.afterEach( async ( { requestUtils } ) => {
await requestUtils.deleteAllMedia();
} );

test( 'reports the correct count on first upload and removes a deleted item from the grid', async ( {
page,
admin,
} ) => {
await admin.createNewPost( { showWelcomeGuide: false } );

// `wp.media` is enqueued on the post editing screen.
await page.waitForFunction(
() => window.wp && window.wp.media && window.wp.media.featuredImage
);

// The Featured Image modal opens on the Upload tab.
await page.evaluate( () => window.wp.media.featuredImage.frame().open() );

const modal = page.locator( '.media-modal' );
await expect( modal ).toBeVisible();

await modal
.locator( 'input[type="file"]' )
.setInputFiles( TEST_IMAGE );

await page.evaluate( () => window.wp.media.frame.content.mode( 'browse' ) );

await expect(
modal.locator( '.attachments .attachment' )
).toHaveCount( 1 );

// The uploaded image must be counted once, not once per collection it
// belongs to (mirrored query + auto-selected selection).
await expect( modal.locator( '.load-more-count' ) ).toHaveText(

Check failure on line 63 in tests/e2e/specs/featured-image-modal.test.js

View workflow job for this annotation

GitHub Actions / E2E Tests / SCRIPT_DEBUG enabled

[chromium] › tests/e2e/specs/featured-image-modal.test.js:34:6 › Featured image modal media count and deletion › reports the correct count on first upload and removes a deleted item from the grid

1) [chromium] › tests/e2e/specs/featured-image-modal.test.js:34:6 › Featured image modal media count and deletion › reports the correct count on first upload and removes a deleted item from the grid Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(locator).toHaveText(expected) failed Locator: locator('.media-modal').locator('.load-more-count') Expected: "Showing 1 of 1 media items" Timeout: 5000ms Error: element(s) not found Call log: - Expect "toHaveText" with timeout 5000ms - waiting for locator('.media-modal').locator('.load-more-count') 61 | // The uploaded image must be counted once, not once per collection it 62 | // belongs to (mirrored query + auto-selected selection). > 63 | await expect( modal.locator( '.load-more-count' ) ).toHaveText( | ^ 64 | 'Showing 1 of 1 media items' 65 | ); 66 | at /home/runner/work/wordpress-develop/wordpress-develop/tests/e2e/specs/featured-image-modal.test.js:63:55

Check failure on line 63 in tests/e2e/specs/featured-image-modal.test.js

View workflow job for this annotation

GitHub Actions / E2E Tests / SCRIPT_DEBUG enabled

[chromium] › tests/e2e/specs/featured-image-modal.test.js:34:6 › Featured image modal media count and deletion › reports the correct count on first upload and removes a deleted item from the grid

1) [chromium] › tests/e2e/specs/featured-image-modal.test.js:34:6 › Featured image modal media count and deletion › reports the correct count on first upload and removes a deleted item from the grid Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(locator).toHaveText(expected) failed Locator: locator('.media-modal').locator('.load-more-count') Expected: "Showing 1 of 1 media items" Timeout: 5000ms Error: element(s) not found Call log: - Expect "toHaveText" with timeout 5000ms - waiting for locator('.media-modal').locator('.load-more-count') 61 | // The uploaded image must be counted once, not once per collection it 62 | // belongs to (mirrored query + auto-selected selection). > 63 | await expect( modal.locator( '.load-more-count' ) ).toHaveText( | ^ 64 | 'Showing 1 of 1 media items' 65 | ); 66 | at /home/runner/work/wordpress-develop/wordpress-develop/tests/e2e/specs/featured-image-modal.test.js:63:55

Check failure on line 63 in tests/e2e/specs/featured-image-modal.test.js

View workflow job for this annotation

GitHub Actions / E2E Tests / SCRIPT_DEBUG enabled

[chromium] › tests/e2e/specs/featured-image-modal.test.js:34:6 › Featured image modal media count and deletion › reports the correct count on first upload and removes a deleted item from the grid

1) [chromium] › tests/e2e/specs/featured-image-modal.test.js:34:6 › Featured image modal media count and deletion › reports the correct count on first upload and removes a deleted item from the grid Error: expect(locator).toHaveText(expected) failed Locator: locator('.media-modal').locator('.load-more-count') Expected: "Showing 1 of 1 media items" Timeout: 5000ms Error: element(s) not found Call log: - Expect "toHaveText" with timeout 5000ms - waiting for locator('.media-modal').locator('.load-more-count') 61 | // The uploaded image must be counted once, not once per collection it 62 | // belongs to (mirrored query + auto-selected selection). > 63 | await expect( modal.locator( '.load-more-count' ) ).toHaveText( | ^ 64 | 'Showing 1 of 1 media items' 65 | ); 66 | at /home/runner/work/wordpress-develop/wordpress-develop/tests/e2e/specs/featured-image-modal.test.js:63:55

Check failure on line 63 in tests/e2e/specs/featured-image-modal.test.js

View workflow job for this annotation

GitHub Actions / E2E Tests / SCRIPT_DEBUG disabled

[chromium] › tests/e2e/specs/featured-image-modal.test.js:34:6 › Featured image modal media count and deletion › reports the correct count on first upload and removes a deleted item from the grid

1) [chromium] › tests/e2e/specs/featured-image-modal.test.js:34:6 › Featured image modal media count and deletion › reports the correct count on first upload and removes a deleted item from the grid Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(locator).toHaveText(expected) failed Locator: locator('.media-modal').locator('.load-more-count') Expected: "Showing 1 of 1 media items" Timeout: 5000ms Error: element(s) not found Call log: - Expect "toHaveText" with timeout 5000ms - waiting for locator('.media-modal').locator('.load-more-count') 61 | // The uploaded image must be counted once, not once per collection it 62 | // belongs to (mirrored query + auto-selected selection). > 63 | await expect( modal.locator( '.load-more-count' ) ).toHaveText( | ^ 64 | 'Showing 1 of 1 media items' 65 | ); 66 | at /home/runner/work/wordpress-develop/wordpress-develop/tests/e2e/specs/featured-image-modal.test.js:63:55

Check failure on line 63 in tests/e2e/specs/featured-image-modal.test.js

View workflow job for this annotation

GitHub Actions / E2E Tests / SCRIPT_DEBUG disabled

[chromium] › tests/e2e/specs/featured-image-modal.test.js:34:6 › Featured image modal media count and deletion › reports the correct count on first upload and removes a deleted item from the grid

1) [chromium] › tests/e2e/specs/featured-image-modal.test.js:34:6 › Featured image modal media count and deletion › reports the correct count on first upload and removes a deleted item from the grid Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: expect(locator).toHaveText(expected) failed Locator: locator('.media-modal').locator('.load-more-count') Expected: "Showing 1 of 1 media items" Timeout: 5000ms Error: element(s) not found Call log: - Expect "toHaveText" with timeout 5000ms - waiting for locator('.media-modal').locator('.load-more-count') 61 | // The uploaded image must be counted once, not once per collection it 62 | // belongs to (mirrored query + auto-selected selection). > 63 | await expect( modal.locator( '.load-more-count' ) ).toHaveText( | ^ 64 | 'Showing 1 of 1 media items' 65 | ); 66 | at /home/runner/work/wordpress-develop/wordpress-develop/tests/e2e/specs/featured-image-modal.test.js:63:55

Check failure on line 63 in tests/e2e/specs/featured-image-modal.test.js

View workflow job for this annotation

GitHub Actions / E2E Tests / SCRIPT_DEBUG disabled

[chromium] › tests/e2e/specs/featured-image-modal.test.js:34:6 › Featured image modal media count and deletion › reports the correct count on first upload and removes a deleted item from the grid

1) [chromium] › tests/e2e/specs/featured-image-modal.test.js:34:6 › Featured image modal media count and deletion › reports the correct count on first upload and removes a deleted item from the grid Error: expect(locator).toHaveText(expected) failed Locator: locator('.media-modal').locator('.load-more-count') Expected: "Showing 1 of 1 media items" Timeout: 5000ms Error: element(s) not found Call log: - Expect "toHaveText" with timeout 5000ms - waiting for locator('.media-modal').locator('.load-more-count') 61 | // The uploaded image must be counted once, not once per collection it 62 | // belongs to (mirrored query + auto-selected selection). > 63 | await expect( modal.locator( '.load-more-count' ) ).toHaveText( | ^ 64 | 'Showing 1 of 1 media items' 65 | ); 66 | at /home/runner/work/wordpress-develop/wordpress-develop/tests/e2e/specs/featured-image-modal.test.js:63:55
'Showing 1 of 1 media items'
);

page.on( 'dialog', ( dialog ) => dialog.accept() );

// The uploaded image is auto-selected, so its details are already shown.
await modal
.locator( '.attachment-details .delete-attachment' )
.click();

// The deleted attachment must not linger in the grid.
await expect(
modal.locator( '.attachments .attachment' )
).toHaveCount( 0 );
} );
} );
Loading