Skip to content

Conversation

@nshirley
Copy link
Contributor

@nshirley nshirley commented Dec 9, 2025

Because

  • Moving/re-architecting email code to libs/ meant we needed new tests

This pull request

  • Adds tests for libs/accounts/email-renderer and libs/accounts/email-sender

Issue that this pull request solves

Closes: FXA-12579

Checklist

Put an x in the boxes that apply

  • My commit is GPG signed.
  • If applicable, I have modified or added tests which pass locally.
  • I have added necessary documentation (if appropriate).
  • I have verified that my changes render correctly in RTL (if appropriate).

Screenshots (Optional)

Please attach the screenshots of the changes made in case of change in user interface.

Other information (Optional)

Any other information that is important to this pull request.

const now = Date.now();

// sort to descending order to guarantee latest bounces are processed first
bounces.sort((a, b) => b.createdAt - a.createdAt);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original implementation had a note that there was an assumption that records come in order by createdAt, but to ensure we always process bounces in that way I figured it makes sense to explicitly order them here.

const BOUNCE_TYPE_HARD = 1;
const BOUNCE_TYPE_SOFT = 2;
const BOUNCE_TYPE_COMPLAINT = 3;
export const BOUNCE_TYPE_HARD = 1;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to use these in the test so it made sense to export them

};
const bounces = new Bounces(config, db);

// internally, applyRules returns tallies, but it's not returned by check(),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel this comment has some more to it than I initially said - applyRules is also a private function so we're having to mock the db to also make this testable. Basically, core business logic is locked behind the private accessor and is difficult to test as a result. It would be nice to make applyRules public and/or a pure function as it would make testing a lot more straight forward.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that makes sense. Can we do that here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense to me. Agreed, that testing it directly is better.


beforeEach(() => {
// Mock Date.now() to return a consistent value for time-based tests
jest.spyOn(Date, 'now').mockReturnValue(mockNow);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't exactly like having to monkey patch this - we could get around/better test if the Bounces class had a systemClock: { now: () => number} parameter which was defaulted internally to Date. Kind of a nit-picky thing but would help make it clear that the module has a time component internally

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually think this spy has caused problems before. I like the suggestion. Want to do that in a follow up?

"outputs": [
"{projectRoot}/public/en/auth.ftl"
]
"inputs": ["{projectRoot}/gruntfile.js", "{projectRoot}/src/**/en.ftl"],
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Formatting because I added the dependsOn and 'format on save' did it's thing. Let me know if I should revert this!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's okay! I feel I've been seeing these formatting changes more and more recently... We should really get to the bottom of this as I team. I don't understand why this is happening, since we should all be using the same prettier configs and format on commit and format on save should essentially the same.

@nshirley nshirley force-pushed the FXA-12579 branch 2 times, most recently from 52b34fb to 2bec955 Compare December 9, 2025 21:50
});
}

renderNewDeviceLoginStrapi(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I was testing how strapi works with the new flow here - I can remove this if it doesn't need to be here yet

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's good to test this. It's a valid 'state' that can be rendered.

Copy link
Contributor Author

@nshirley nshirley Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left a comment in this, but also want to explicitly call this out - snapshots are going to be good long-term as it allows us to quickly identify nuanced, unintentional changes to email templates and partials.

However, this pattern of snapshots is not going to be fun long-term. We cannot specify a directory to save a snapshot (it's always relative to test file) and so, all of these get put into one massive 18k+ line snapshot file. In the future, it would be BEST to be able to upgrade Storybook (maybe we can just upgrade this package?) since it would allow us to leverage snapshots directly on the storybooks. Snapshots would be more focused at that point, and per template so they're easier to read.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add this info to the upgrade storybook ticket? https://mozilla-hub.atlassian.net/browse/FXA-8765

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The more I've thought about this, the less I like it. The only other "solution" I can think for some what manageable tests until we can upgrade storybook is to explicitly test for email subject, template, version, etc. But the biggest part we care about is the html and that would be difficult to test without explicit "for this template, we need to make sure this element exists with this body."

Which I suppose I could do, at least getting the groundwork down, then future updates and tests won't be so tedious... I'm open to suggestions!

@nshirley nshirley marked this pull request as ready for review December 10, 2025 20:10
@nshirley nshirley requested a review from a team as a code owner December 10, 2025 20:10
privacyUrl: string;

/** The current support url. */
supportUrl: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these referenced in the layout template? I'm not seeing them.


return {
langauge: selectedLocale,
language: selectedLocale,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

<%- include('/partials/userInfo/index.txt') %>

passwordResetAccountRecovery-regen-required-txt-1 = "We logged you out of all your synced devices. We created a new account recovery key to replace the one you used. You can change it in your account settings:"
passwordResetAccountRecovery-information-txt = "We logged you out of all your synced devices. We created a new account recovery key to replace the one you used. You can change it in your account settings:"
Copy link
Contributor

@dschom dschom Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, did this mistake get picked up by the tests?

@@ -1,11 +1,11 @@
postChangeTwoStepAuthentication-title-2 = "Two-step authentication has been updated"
Copy link
Contributor

@dschom dschom Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this suffixes a little suspicous... Do when know when/why they were added?

}
},
"test-unit": {
"dependsOn": ["l10n-merge"],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for spotting this.

Copy link
Contributor

@dschom dschom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes look great. I'm a big fan of the snapshot approach over the what we had before.


beforeEach(() => {
// Mock Date.now() to return a consistent value for time-based tests
jest.spyOn(Date, 'now').mockReturnValue(mockNow);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually think this spy has caused problems before. I like the suggestion. Want to do that in a follow up?

let mockBounces: jest.Mocked<Bounces>;
let mockStatsd: jest.Mocked<StatsD>;
let mockLogger: jest.Mocked<ILogger>;
let mockTransport: any;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we give it a type of some sort?

};
const bounces = new Bounces(config, db);

// internally, applyRules returns tallies, but it's not returned by check(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that makes sense. Can we do that here?

};
const bounces = new Bounces(config, db);

// internally, applyRules returns tallies, but it's not returned by check(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense to me. Agreed, that testing it directly is better.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants