Skip to content
Merged
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
2 changes: 1 addition & 1 deletion domains/etsy.com/set_favorite.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
if (initial.error) return lookupError(initial, false, null);
if (initial.favorited === input.favorited) return { status: "ok", listing_id: id, previous_favorited: initial.favorited, favorited: initial.favorited, changed: false, mutation_attempted: false };
// The listing page's own button first; otherwise a result card's button for the same listing.
const buttons = [...document.querySelectorAll(`[data-ui="favorite-listing-button"][data-listing-id="${id}"]`)].filter(b => b.getClientRects().length);
const buttons = [...document.querySelectorAll(`[data-ui="favorite-listing-button"][data-listing-id="${id}"], button.listing-page-favorite-button[data-listing-id="${id}"]`)].filter(b => b.getClientRects().length);
const button = buttons.find(b => !b.closest("[data-listing-card-v2], [data-palette-listing-id]")) || buttons[0];
if (!button) return fail("listing_not_on_page", `This page shows no favorite button for listing ${id}; open https://www.etsy.com/listing/${id} (or a search page that shows it) and call again. Nothing was changed.`, { previous_favorited: initial.favorited });
// An observer, because listing pages fill the resource-timing buffer and later entries never reach it.
Expand Down
2 changes: 1 addition & 1 deletion registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -1769,7 +1769,7 @@
"url_patterns_reason": "Narrowed to www.etsy.com: the marketplace (search, listings, cart, favorites) lives entirely there and etsy.com redirects to it; other subdomains (help center, forums) are unrelated products where the page tools' relative requests would fail.",
"status": "draft",
"last_verified": null,
"notes": "Signed-in only: records the initial favorite state, no-op if it already matches, otherwise presses the listing's favorite button on the current page once (listing page or a search page showing it) and confirms. Never run signed in (no Etsy account available); signed out returns not_logged_in and presses nothing."
"notes": "Signed-in only: records the initial favorite state, no-op if it already matches, otherwise presses the listing's favorite button on the current page once (listing page or a search page showing it) and confirms. The listing page's own heart is button.listing-page-favorite-button (no data-ui attribute), next to an Add to collection button with the same listing id that is never pressed. Author live check on 2026-10-27 (not independent QA), signed in on a listing page: false to true, a no-op repeat, then true to false, each read back with get_favorite_status and the account left as it started. Signed out returns not_logged_in and presses nothing."
},
{
"domain": "etsy.com",
Expand Down
5 changes: 3 additions & 2 deletions tests/etsy-tools.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@ test("get_favorite_status: reads Etsy's favorites map for each listing", async (

// Simulates Etsy's favorite buttons on a page: a press sends the favorites request and toggles the state.
const favoriteButtons = (behaviour = "toggle") => (doc, path, site) => {
for (const button of doc.querySelectorAll('[data-ui="favorite-listing-button"]')) {
for (const button of doc.querySelectorAll('[data-ui="favorite-listing-button"], .listing-page-favorite-button, [data-add-to-collection-button]')) {
button.addEventListener("click", function () {
site.presses = (site.presses || 0) + 1;
site.pressed = this;
Expand Down Expand Up @@ -675,6 +675,7 @@ for (const [from, to] of [[false, true], [true, false]]) {
const result = await h.run({ listing_id: "1000000003", favorited: to });
assert.deepEqual(result, { status: "ok", listing_id: "1000000003", previous_favorited: from, favorited: to, changed: true, mutation_attempted: true });
assert.equal(h.site.presses, 1);
assert.equal(h.site.pressed.getAttribute("data-testid"), "favorite-heart", "the heart, not Add to collection");
assert.deepEqual(h.calls.navigations, [], "page tools never navigate");
});
}
Expand Down Expand Up @@ -704,7 +705,7 @@ test("set_favorite: presses the listing page's own button rather than a recommen
const h = favoriteHarness({ signedIn: true, url: `${ORIGIN}/listing/1000000001` });
const result = await h.run({ listing_id: "1000000001", favorited: true });
assert.equal(result.changed, true);
assert.equal(h.site.pressed.hasAttribute("data-always-show"), true);
assert.equal(h.site.pressed.getAttribute("data-testid"), "favorite-heart");
});

test("set_favorite: a search result card's button is used when the listing page is not open", async () => {
Expand Down
3 changes: 2 additions & 1 deletion tests/fixtures/etsy/listing-classic.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
<main>
<h1 class="wt-text-body-01">Fabricated Leather Pet Collar &amp; Tag</h1>
<div data-selector="price-only" data-buy-box-region="price"><p class="wt-text-title-larger"><span class="wt-mr-xs-1">Now</span><span class="wt-screen-reader-only">Price:</span>$18.00+</p><p class="wt-text-caption"><span class="wt-screen-reader-only">Original Price:</span><span class="wt-text-strikethrough"> $30.00+ </span></p><div class="wt-spinner wt-display-none" data-buy-box-price-spinner="">Loading</div></div>
<button data-ui="favorite-listing-button" data-listing-id="1000000001" data-always-show="true">Add to Favorites</button>
<button type="button" aria-label="Add to Favorites" data-accessible-btn-fave="true" data-listing-id="1000000001" data-always-show="true" data-testid="favorite-heart" class="wt-btn listing-page-favorite-button">Add to Favorites</button>
<button class="wt-btn wt-btn--transparent" data-listing-id="1000000001" data-accessible-btn-fave="true" data-add-to-collection-button="true" data-always-show="true">Add to collection</button>
<div data-appears-component-name="variations">
<div data-selector="listing-page-variation" data-variation-number="0">
<label for="variation-selector-0" id="label-variation-selector-0"><span data-label="">Size &amp; Color</span></label>
Expand Down
3 changes: 2 additions & 1 deletion tests/fixtures/etsy/listing-plain.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
</head><body><main>
<h1>Fabricated Blue Vase</h1>
<div data-selector="price-only"><p>$42.00</p></div>
<button data-ui="favorite-listing-button" data-listing-id="1000000003" data-always-show="true">Add to Favorites</button>
<button type="button" aria-label="Add to Favorites" data-accessible-btn-fave="true" data-listing-id="1000000003" data-always-show="true" data-testid="favorite-heart" class="wt-btn listing-page-favorite-button">Add to Favorites</button>
<button class="wt-btn wt-btn--transparent" data-listing-id="1000000003" data-accessible-btn-fave="true" data-add-to-collection-button="true" data-always-show="true">Add to collection</button>
<form action="https://www.etsy.com/cart/listing.php" method="post"><input type="hidden" name="listing_id" value="1000000003"><input type="hidden" name="quantity" value="1"><button type="submit">Add to cart</button></form>
</main></body></html>
Loading