Skip to content

Commit

Permalink
Merge branch 'main' into local-e2e-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
flozia authored Feb 4, 2025
2 parents 6c099fb + 4166eee commit 8f5034b
Show file tree
Hide file tree
Showing 12 changed files with 281 additions and 202 deletions.
2 changes: 1 addition & 1 deletion locales/sk/settings.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ settings-page-title = Nastavenia { -product-short-name(case: "gen") }
## Breach alert preferences

settings-alert-email-preferences-title = Predvoľby e-mailov
settings-alert-email-preferences-title = Predvoľby emailov
settings-alert-email-preferences-subtitle = Povedzte nám, aké e‑maily chcete dostávať.
settings-alert-preferences-allow-breach-alerts-title = Okamžité upozornenia na únik
settings-alert-preferences-allow-breach-alerts-subtitle = Tieto upozornenia sa odosielajú okamžite po zistení úniku údajov
Expand Down
328 changes: 165 additions & 163 deletions package-lock.json

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,13 @@
"@faker-js/faker": "^9.4.0",
"@google-cloud/bigquery": "^7.9.1",
"@playwright/test": "^1.50.0",
"@storybook/addon-a11y": "^8.5.2",
"@storybook/addon-actions": "^8.5.2",
"@storybook/addon-essentials": "^8.5.2",
"@storybook/addon-interactions": "^8.5.2",
"@storybook/addon-links": "^8.5.2",
"@storybook/nextjs": "^8.5.2",
"@storybook/react": "^8.5.2",
"@storybook/addon-a11y": "^8.5.3",
"@storybook/addon-actions": "^8.5.3",
"@storybook/addon-essentials": "^8.5.3",
"@storybook/addon-interactions": "^8.5.3",
"@storybook/addon-links": "^8.5.3",
"@storybook/nextjs": "^8.5.3",
"@storybook/react": "^8.5.3",
"@storybook/test": "^8.5.2",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.2.0",
Expand Down
Binary file modified public/images/email/mozilla-logo-bw.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,37 @@ import {
deleteSubscriberChurns,
} from "../../../../../../db/tables/subscriber_churns";
import { SubscriberChurnRow } from "knex/types/tables";
import { getServerSession } from "../../../../../functions/server/getServerSession";
import { isAdmin } from "../../../../../api/utils/auth";

/**
* Helper function to perform session + admin check.
* Returns true if the current session belongs to an admin user.
*/
async function isAuthorized(): Promise<boolean> {
const session = await getServerSession();
return Boolean(session?.user?.email && isAdmin(session.user.email));
}

export async function getAllChurns() {
if (!(await isAuthorized())) {
return null;
}
return getAllSubscriberChurns();
}

export async function upsertAllChurns(
churningSubscribers: SubscriberChurnRow[],
) {
if (!(await isAuthorized())) {
return null;
}
return upsertSubscriberChurns(churningSubscribers);
}

export async function clearAllChurns() {
if (!(await isAuthorized())) {
return null;
}
return deleteSubscriberChurns();
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default async function DevPage() {

return (
<ChurnAdmin
churningSubscribers={await getAllChurns()}
churningSubscribers={(await getAllChurns()) ?? []}
churnsToEmail={await getChurnsToEmail()}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,15 @@ it("includes a link to the terms on the renewal page", () => {

it("confirms the renewal after it's applied", async () => {
const user = userEvent.setup();
const applyCouponPromise = new Promise((resolve) => {
resolve({
success: true,
});
});
const PlusExpirationView = composeStory(HappyPath, Meta);
render(
<PlusExpirationView
applyCouponAction={jest.fn().mockResolvedValue({ success: true })}
applyCouponAction={jest.fn().mockReturnValue(applyCouponPromise)}
/>,
);

Expand All @@ -49,6 +54,7 @@ it("confirms the renewal after it's applied", async () => {
name: "Renew subscription",
});
await user.click(renewalButton);
await applyCouponPromise;

expect(
screen.getByRole("heading", {
Expand All @@ -59,16 +65,20 @@ it("confirms the renewal after it's applied", async () => {

it("shows an error if applying the coupon failed", async () => {
const user = userEvent.setup();
const applyCouponPromise = new Promise((resolve) => {
resolve({
success: false,
error: "apply_renewal_coupon_error",
});
});
const PlusExpirationView = composeStory(HappyPath, Meta);
render(
<PlusExpirationView
applyCouponAction={jest.fn().mockResolvedValue({
success: false,
error: "apply_renewal_coupon_error",
})}
applyCouponAction={jest.fn().mockReturnValue(applyCouponPromise)}
/>,
);

await applyCouponPromise;
expect(
screen.queryByText(/Couldnt renew subscription./),
).not.toBeInTheDocument();
Expand All @@ -83,20 +93,24 @@ it("shows an error if applying the coupon failed", async () => {

it("hides the error after dismissing it", async () => {
const user = userEvent.setup();
const applyCouponErrorPromise = new Promise((resolve) => {
resolve({
success: false,
error: "apply_renewal_coupon_error",
});
});
const PlusExpirationView = composeStory(HappyPath, Meta);
render(
<PlusExpirationView
applyCouponAction={jest.fn().mockResolvedValue({
success: false,
error: "apply_renewal_coupon_error",
})}
applyCouponAction={jest.fn().mockReturnValue(applyCouponErrorPromise)}
/>,
);

const renewalButton = screen.getByRole("button", {
name: "Renew subscription",
});
await user.click(renewalButton);
await applyCouponErrorPromise;

expect(screen.getByText(/Couldnt renew subscription./)).toBeInTheDocument();

Expand All @@ -110,27 +124,37 @@ it("hides the error after dismissing it", async () => {
it("allows retrying after an error", async () => {
const user = userEvent.setup();
const PlusExpirationView = composeStory(HappyPath, Meta);
const applyCouponErrorPromise = new Promise((resolve) => {
resolve({
success: false,
error: "apply_renewal_coupon_error",
});
});
const applyCouponSuccessPromise = new Promise((resolve) => {
resolve({
success: true,
});
});
render(
<PlusExpirationView
applyCouponAction={jest
.fn()
.mockResolvedValueOnce({
success: false,
error: "apply_renewal_coupon_error",
})
.mockResolvedValueOnce({ success: true })}
.mockReturnValueOnce(applyCouponErrorPromise)
.mockReturnValueOnce(applyCouponSuccessPromise)}
/>,
);

const renewalButton = screen.getByRole("button", {
name: "Renew subscription",
});
await user.click(renewalButton);
await applyCouponErrorPromise;

expect(screen.getByText(/Couldnt renew subscription./)).toBeInTheDocument();

const retryButton = screen.getByRole("button", { name: "Try again" });
await user.click(retryButton);
await applyCouponSuccessPromise;
expect(
screen.queryByText(/Couldnt renew subscription./),
).not.toBeInTheDocument();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { logger } from "../../../../../functions/server/logging";
import { checkChurnCouponCode } from "../../../../../functions/server/applyCoupon";
import { applyRenewalCoupon } from "./actions";
import { getEnabledFeatureFlags } from "../../../../../../db/tables/featureFlags";
import { getChurnsToEmail } from "../../../../../../db/tables/subscriber_churns";
import { getUpcomingChurns } from "../../../../../../db/tables/subscriber_churns";

export default async function PlusExpirationPage() {
const session = await getServerSession();
Expand Down Expand Up @@ -41,7 +41,7 @@ export default async function PlusExpirationPage() {
}

const couponCheckResult = await checkChurnCouponCode(subscriber);
const subscribersToEmail = await getChurnsToEmail();
const expiringSubscriptions = await getUpcomingChurns();

return (
<View
Expand All @@ -50,9 +50,9 @@ export default async function PlusExpirationPage() {
applyCouponAction={applyRenewalCoupon}
manageSubscriptionsUrl={process.env.FXA_SUBSCRIPTIONS_URL!}
isOnExpirationList={
typeof subscribersToEmail.find(
(subscriberToEmail) =>
subscriberToEmail.userid === subscriber.fxa_uid,
typeof expiringSubscriptions.find(
(expiringSubscription) =>
expiringSubscription.userid === subscriber.fxa_uid,
) !== "undefined"
}
/>
Expand Down
9 changes: 2 additions & 7 deletions src/app/(proper_react)/images/mozilla-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions src/app/components/client/csat_survey/CsatSurvey.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ describe("CSAT survey banner: Automatic Removal", () => {
expect(answerButton).toBeInTheDocument();
});

it.each([90, 180, 351])(
it.each([90, 180, 351, 716])(
"displays the survey to users with automatic data removal enabled for at least n days",
(dayCount) => {
const ComposedCsatSurvey = composeStory(CsatSurveyAutomaticRemoval, Meta);
Expand Down Expand Up @@ -115,7 +115,7 @@ describe("CSAT survey banner: Automatic Removal", () => {
it("shows the correct follow-up feedback link for response “Satisfied”", async () => {
const user = userEvent.setup();
const ComposedCsatSurvey = composeStory(CsatSurveyAutomaticRemoval, Meta);
render(<ComposedCsatSurvey elapsedTimeInDaysSinceInitialScan={91} />);
render(<ComposedCsatSurvey elapsedTimeInDaysSinceInitialScan={716} />);

const answerButton = screen.getByRole("button", {
name: "Satisfied",
Expand All @@ -128,7 +128,7 @@ describe("CSAT survey banner: Automatic Removal", () => {
expect(feedbackLink).toBeInTheDocument();
expect(feedbackLink).toHaveAttribute(
"href",
"https://survey.alchemer.com/s3/7718223/fbbb597a762a",
"https://survey.alchemer.com/s3/8176616/091e554aa6ab",
);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
} from "./csatSurvey";

export type AutomaticRemovalVariation = {
id: "initial" | "3-months" | "6-months" | "12-months";
id: "initial" | "3-months" | "6-months" | "12-months" | "24-months";
showForUser: UserType[];
showOnTab: TabType[];
daysThreshold: number;
Expand Down Expand Up @@ -87,6 +87,20 @@ const surveyData: SurveyData = {
"very-satisfied": "https://survey.alchemer.com/s3/7718562/002e20b6b82f",
},
},
{
id: "24-months",
showForUser: ["plus-user"],
showOnTab: ["fixed"],
daysThreshold: 716,
followUpSurveyOptions: {
"very-dissatisfied":
"https://survey.alchemer.com/s3/8176616/edb0c3f18778",
dissatisfied: "https://survey.alchemer.com/s3/8176616/9b6ca1d007a5",
neutral: "https://survey.alchemer.com/s3/8176616/37955cef0c5e",
satisfied: "https://survey.alchemer.com/s3/8176616/091e554aa6ab",
"very-satisfied": "https://survey.alchemer.com/s3/8176616/7ac85d1249cd",
},
},
],
};

Expand Down
24 changes: 24 additions & 0 deletions src/db/tables/subscriber_churns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,29 @@ async function getAllSubscriberChurns(): Promise<SubscriberChurnRow[]> {
}
}

async function getUpcomingChurns(): Promise<Array<SubscriberChurnRow>> {
try {
const res = await knex("subscriber_churns")
.select("*")
.where("intervl", "year")
.whereNotNull("current_period_end")
.where(knex.raw("current_period_end::timestamptz"), ">=", knex.fn.now())
.where(
knex.raw("current_period_end::timestamptz"),
"<=",
knex.raw("CURRENT_TIMESTAMP + interval '7 days'"),
);

logger.info("get_upcoming_churns_success", { count: res.length });
return res;
} catch (e) {
logger.error("get_upcoming_churns_error", {
error: JSON.stringify(e),
});
throw e;
}
}

async function getChurnsToEmail(): Promise<
Array<SubscriberChurnRow & SubscriberRow>
> {
Expand Down Expand Up @@ -92,5 +115,6 @@ export {
upsertSubscriberChurns,
getAllSubscriberChurns,
deleteSubscriberChurns,
getUpcomingChurns,
getChurnsToEmail,
};

0 comments on commit 8f5034b

Please sign in to comment.