Merge branch 'unstable' into codex/extend-tag-pill-rendering-and-add-menu-component

This commit is contained in:
thePR0M3TH3AN authored and GitHub committed 2025-10-25 17:29:39 -04:00
commit 6144a84f7b
14 files changed
+801 -39

No files matched your search

+74
View File
@@ -70,3 +70,77 @@ test("handleModerationOverride decorates stored and current videos then refreshe
assert.equal(currentVideo.moderation.blockAutoplay, false);
assert.equal(currentVideo.moderation.blurThumbnail, false);
});
test("handleModerationHide clears overrides and re-applies hidden state", async (t) => {
withMockedNostrTools(t);
const app = await createModerationAppHarness();
app.getActiveModerationThresholds = () => ({
autoplayBlockThreshold: Number.POSITIVE_INFINITY,
blurThreshold: Number.POSITIVE_INFINITY,
trustedMuteHideThreshold: 1,
trustedSpamHideThreshold: Number.POSITIVE_INFINITY,
});
const videoId = "b".repeat(64);
const incomingVideo = {
id: videoId,
moderation: {
trustedMuted: true,
trustedMuteCount: 1,
trustedMuters: [MUTER_HEX],
trustedCount: 0,
reportType: "nudity",
},
};
const storedVideo = {
id: videoId,
moderation: {
trustedMuted: true,
trustedMuteCount: 1,
trustedMuters: [MUTER_HEX],
trustedCount: 0,
reportType: "nudity",
},
};
const currentVideo = {
id: videoId,
moderation: {
trustedMuted: true,
trustedMuteCount: 1,
trustedMuters: [MUTER_HEX],
trustedCount: 0,
reportType: "nudity",
},
};
app.videosMap.set(videoId, storedVideo);
app.currentVideo = currentVideo;
app.decorateVideoModeration(incomingVideo);
app.decorateVideoModeration(storedVideo);
app.decorateVideoModeration(currentVideo);
const card = {
refreshModerationUi() {
/* noop */
},
};
app.handleModerationOverride({ video: incomingVideo, card });
assert.equal(storedVideo.moderation.viewerOverride?.showAnyway, true);
assert.equal(currentVideo.moderation.viewerOverride?.showAnyway, true);
const result = app.handleModerationHide({ video: incomingVideo, card });
assert.equal(result, true);
assert.equal(incomingVideo.moderation.viewerOverride, undefined);
assert.equal(storedVideo.moderation.viewerOverride, undefined);
assert.equal(currentVideo.moderation.viewerOverride, undefined);
assert.equal(incomingVideo.moderation.hidden, true);
assert.equal(storedVideo.moderation.hidden, true);
assert.equal(currentVideo.moderation.hidden, true);
});
@@ -197,6 +197,7 @@ export async function createModerationAppHarness() {
app.deriveModerationTrustedCount = Application.prototype.deriveModerationTrustedCount;
app.getReporterDisplayName = Application.prototype.getReporterDisplayName;
app.handleModerationOverride = Application.prototype.handleModerationOverride;
app.handleModerationHide = Application.prototype.handleModerationHide;
app.videosMap = new Map();
app.currentVideo = null;
+13
View File
@@ -94,6 +94,8 @@ test("moderation stage enforces admin lists without whitelist bypass", async ()
const whitelistedItem = result[0];
assert.equal(whitelistedItem.video.moderation.blockAutoplay, true);
assert.equal(whitelistedItem.video.moderation.blurThumbnail, true);
assert.equal(whitelistedItem.video.moderation.blurReason, "trusted-report");
assert.equal(whitelistedItem.metadata.moderation.blurReason, "trusted-report");
assert.equal(whitelistedItem.video.moderation.adminWhitelist, true);
assert.equal(whitelistedItem.video.moderation.adminWhitelistBypass, false);
assert.equal(whitelistedItem.metadata.moderation.adminWhitelistBypass, false);
@@ -101,6 +103,8 @@ test("moderation stage enforces admin lists without whitelist bypass", async ()
const normalItem = result[1];
assert.equal(normalItem.video.moderation.blockAutoplay, true);
assert.equal(normalItem.video.moderation.blurThumbnail, true);
assert.equal(normalItem.video.moderation.blurReason, "trusted-report");
assert.equal(normalItem.metadata.moderation.blurReason, "trusted-report");
const reasons = why.map((entry) => entry.reason);
assert(reasons.includes("viewer-block"));
@@ -211,11 +215,14 @@ test("moderation stage applies provided thresholds", async () => {
assert.equal(strictResult.length, 1);
assert.equal(strictResult[0].video.moderation.blockAutoplay, false);
assert.equal(strictResult[0].video.moderation.blurThumbnail, false);
assert.equal(strictResult[0].video.moderation.blurReason, undefined);
const relaxedResult = await relaxedStage(items, {});
assert.equal(relaxedResult.length, 1);
assert.equal(relaxedResult[0].video.moderation.blockAutoplay, true);
assert.equal(relaxedResult[0].video.moderation.blurThumbnail, true);
assert.equal(relaxedResult[0].video.moderation.blurReason, "trusted-report");
assert.equal(relaxedResult[0].metadata.moderation.blurReason, "trusted-report");
});
test("moderation stage propagates whitelist, muters, and threshold updates", async () => {
@@ -315,14 +322,18 @@ test("moderation stage propagates whitelist, muters, and threshold updates", asy
assert.equal(whitelistedItem.metadata.moderation.adminWhitelist, true);
assert.equal(whitelistedItem.metadata.moderation.blockAutoplay, true);
assert.equal(whitelistedItem.metadata.moderation.blurThumbnail, true);
assert.equal(whitelistedItem.metadata.moderation.blurReason, "trusted-report");
assert.equal(whitelistedItem.video.moderation.adminWhitelistBypass, false);
assert.equal(whitelistedItem.video.moderation.blurReason, "trusted-report");
assert.equal(mutedItem.metadata.moderation.trustedMuted, true);
assert.deepEqual(mutedItem.metadata.moderation.trustedMuters, [muterHex]);
assert.equal(mutedItem.metadata.moderation.blockAutoplay, true);
assert.equal(mutedItem.metadata.moderation.blurThumbnail, true);
assert.equal(mutedItem.metadata.moderation.blurReason, "trusted-report");
assert.equal(mutedItem.video.moderation.trustedMuted, true);
assert.deepEqual(mutedItem.video.moderation.trustedMuters, [muterHex]);
assert.equal(mutedItem.video.moderation.blurReason, "trusted-report");
state.summaryById.set("muted-video", {
eventId: "muted-video",
@@ -342,9 +353,11 @@ test("moderation stage propagates whitelist, muters, and threshold updates", asy
assert.deepEqual(updatedMuted.metadata.moderation.trustedMuters, []);
assert.equal(updatedMuted.metadata.moderation.blockAutoplay, false);
assert.equal(updatedMuted.metadata.moderation.blurThumbnail, false);
assert.equal(updatedMuted.metadata.moderation.blurReason, undefined);
assert.equal(updatedMuted.video.moderation.trustedMuted, false);
assert.equal(updatedMuted.video.moderation.blockAutoplay, false);
assert.equal(updatedMuted.video.moderation.blurThumbnail, false);
assert.equal(updatedMuted.video.moderation.blurReason, undefined);
});
test("moderation stage clears cached reporters and muters after service signals", async () => {
+132
View File
@@ -258,3 +258,135 @@ test(
assert.ok(card.moderationBadgeEl.textContent.includes("Showing despite"));
},
);
test("VideoCard blurs thumbnails when trusted mute triggers without reports", async (t) => {
const { document } = setupDom(t);
withMockedNostrTools(t);
const app = await createModerationAppHarness();
app.getActiveModerationThresholds = () => ({
autoplayBlockThreshold: Number.POSITIVE_INFINITY,
blurThreshold: Number.POSITIVE_INFINITY,
trustedMuteHideThreshold: 2,
trustedSpamHideThreshold: Number.POSITIVE_INFINITY,
});
const videoId = "c".repeat(64);
const video = {
id: videoId,
title: "Muted Clip",
pubkey: "d".repeat(64),
moderation: {
trustedMuted: true,
trustedMuteCount: 1,
blockAutoplay: false,
blurThumbnail: false,
trustedCount: 0,
reportType: "nudity",
},
};
app.videosMap.set(video.id, video);
app.currentVideo = video;
app.decorateVideoModeration(video);
const card = new VideoCard({
document,
video,
formatters: {
formatTimeAgo: () => "moments ago",
},
helpers: {
isMagnetSupported: () => false,
},
});
document.body.appendChild(card.getRoot());
assert.equal(video.moderation.blurThumbnail, true);
assert.equal(video.moderation.blurReason, "trusted-mute");
assert.equal(card.getModerationContext().activeBlur, true);
assert.equal(card.thumbnailEl.dataset.thumbnailState, "blurred");
assert.equal(card.authorPicEl.dataset.visualState, "blurred");
assert.equal(card.getRoot().dataset.autoplayPolicy, "blocked");
assert.equal(card.moderationBadgeEl.dataset.moderationState, "trusted-mute");
assert.equal(
card.moderationBadgeTextEl.textContent,
"Autoplay blocked · Muted by a trusted contact",
);
assert.ok(card.moderationHideButton);
assert.equal(
card.moderationHideButton?.dataset?.moderationAction,
"hide",
);
});
test("VideoCard hide action restores trusted mute hide state after override", async (t) => {
const { document } = setupDom(t);
withMockedNostrTools(t);
const app = await createModerationAppHarness();
app.getActiveModerationThresholds = () => ({
autoplayBlockThreshold: Number.POSITIVE_INFINITY,
blurThreshold: Number.POSITIVE_INFINITY,
trustedMuteHideThreshold: 1,
trustedSpamHideThreshold: Number.POSITIVE_INFINITY,
});
const videoId = "d".repeat(64);
const video = {
id: videoId,
title: "Muted Hide Clip",
pubkey: "e".repeat(64),
moderation: {
trustedMuted: true,
trustedMuteCount: 1,
trustedMuters: ["f".repeat(64)],
trustedCount: 0,
reportType: "nudity",
},
};
app.videosMap.set(video.id, video);
app.currentVideo = video;
app.decorateVideoModeration(video);
const card = new VideoCard({
document,
video,
formatters: {
formatTimeAgo: () => "moments ago",
},
helpers: {
isMagnetSupported: () => false,
},
});
document.body.appendChild(card.getRoot());
assert.equal(card.getModerationContext().activeHidden, true);
assert.equal(card.getRoot().dataset.moderationHidden, "true");
card.onModerationOverride = ({ video: overrideVideo, card: overrideCard }) =>
app.handleModerationOverride({ video: overrideVideo, card: overrideCard });
card.moderationActionButton.click();
await new Promise((resolve) => setTimeout(resolve, 0));
const contextAfterOverride = card.getModerationContext();
assert.equal(contextAfterOverride.overrideActive, true);
assert.equal(contextAfterOverride.activeHidden, false);
assert.ok(card.moderationHideButton);
card.onModerationHide = ({ video: targetVideo, card: targetCard }) =>
app.handleModerationHide({ video: targetVideo, card: targetCard });
card.moderationHideButton.click();
await new Promise((resolve) => setTimeout(resolve, 0));
const contextAfterHide = card.getModerationContext();
assert.equal(contextAfterHide.overrideActive, false);
assert.equal(contextAfterHide.activeHidden, true);
assert.equal(card.getRoot().dataset.moderationHidden, "true");
assert.equal(card.moderationHideButton, null);
});
+3
View File
@@ -127,6 +127,7 @@ test.describe("moderation fixtures", () => {
const muteCard = page.locator('[data-test-id="trusted-mute-hide"]');
const badge = muteCard.locator('[data-moderation-badge="true"]');
const thumbnail = muteCard.locator('img[data-video-thumbnail]');
const showAnywayButton = muteCard.getByRole("button", { name: "Show anyway" });
await expect(muteCard).toHaveAttribute("data-moderation-hidden", "true");
@@ -135,6 +136,7 @@ test.describe("moderation fixtures", () => {
await expect(muteCard).toHaveAttribute("data-moderation-trusted-mute", "true");
await expect(muteCard).toHaveAttribute("data-moderation-trusted-mute-count", "1");
await expect(badge).toContainText("Hidden · 1 trusted mute");
await expect(thumbnail).toHaveAttribute("data-thumbnail-state", "blurred");
await expect(showAnywayButton).toBeVisible();
await showAnywayButton.click();
@@ -144,5 +146,6 @@ test.describe("moderation fixtures", () => {
await expect(muteCard.locator('[data-moderation-badge="true"]')).toContainText(
"Showing despite 1 trusted mute",
);
await expect(thumbnail).not.toHaveAttribute("data-thumbnail-state", "blurred");
});
});