Recently I have described hot to testing email flows using Mailosaur. Unfortunately, I must report that Mailosaur uses dark design UI pattern to trick you to sign up to a monthly plan that has 1/20 of the usage limits you expect! The trial period has usage limit of 2000 emails per day, which is so generous, you never hit any limits while trying it out.
The misleading Mailosaur pricing table
When you go to the pricing page to sign up for real, you see the following:
Looks reasonable, right? A simple monthly plan with 1 developer account and 1000 emails per day ... is only $9. Right? WRONG. Small gray font gives the weasel words: "Up to 1000 emails per day" and default being ... only 50 per day.
Ok, how do you increase the daily email limit? You change it in that input field from 50 to 1000. Ooops, you monthly price is now $9 + $25.
Hmm. That is completely different ballpark, the price to get what you think we were getting (up to 1000 emails per day) just went up 4x. Ok, no biggie, let's use the "Most popular Business" monthly plan. This plan says "From 5000 emails per day" which is very generous. You must be thinking how is it so much cheaper than the "Starter" plan for much higher limits?
.
It is not. But the table does not even show the real price. The catch is in the words "Starts at 5 seats". Once you pick the Business plan and go to the checkout page you get hit with $80 per month... because $16 * 5 users = $80 total monthly cost.
Even that is not all. The dark UI Mailosaur patterns continue. When picking the plan to sign up... you don't see the total price. Yup, you pick the new usage limits and do not see the price until you fill everything and proceed to the Payment page.
Ohh, you want to increase your daily email limit above 50? Ok, how about ... you can only increase it to 500 or 750 or 1000?!!! What kind of the step up is this?
Am I crazy, or is this a really shitty way of tricking customers? I do think developers and companies providing services must be paid, but this is just tricking you to pay for a lot less service than you expect.
Do not hit usage limits
Ok, let's see if we can get away with the lowest usage limit of 50 emails per day. One thing that is very annoying: you run your CI tests several times a day, and suddenly hit the email usage limits and all your Mailosaur cy
commands fail with the "Usage limit" errors. Here is how I protected my builds and simply skip the email tests if we are close to the daily usage limit. Let's say at most my Cypress tests generate 10 emails per run. Thus I disable them if we are close to "daily limit - 10" number.
🎁 You can find the full source code shown in this blog post in the repo bahmutov/cypress-sendgrid-mailosaur-example.
First, to get the Mailosaur usage limit, you can hit the API endpoint using the same API key used during email testing.
1 | const axios = require('axios') |
The returned object data.email
has only two properties limit
and current
. In our case the limit: 50
. Let's disable email testing by checking the usage limit before Cypress tests start. From the project config file, grab the usage limits and set the env.skipEmailTests = true
value if we are over the limit.
1 | const { defineConfig } = require('cypress') |
- If we are above the daily usage limit, disable all email testing by setting
config.env.skipEmailTests = true
- If we are approaching the daily usage limit:
- still allow testing if we are using
cypress open
command. This way a developer can still work on email specs
- still allow testing if we are using
In each Cypress spec file, we skip the email test if the skipEmailTests
value is set to true
.
1 | describe('An email', () => { |
The value skipEmailTests
set in the cypress.config.js
is static and is available in every spec right away and allows us to determine which tests to define. If we are at the limit, the tests are showing as pending.
If we are below the usage limit, the tests execute.
Reuse the email
A single test flow can generate multiple emails. For example, during Mercari US testing, we might create a buyer and a seller users. That is two confirmation emails. If the buyer buys an item, both users get an email. The buyer receives an email "You made a sale..." and the seller receives an email "You made a purchase..."
You can imagine how we might write multiple tests based on those 2 emails. Can the seller confirm the shipment by clicking on the item? What if the seller is not logged in into the browser, will the email lead to the "Sign in" screen and then to the right item's page? What about the user: can they go to the order page? Can the buyer that is not logged in click on the email, sign in, and then see their purchase item? Instead of writing separate email flow tests, each generating 4 emails, let's grab the emails just once and reuse them.
In my example, I will use the following confirmation email from bahmutov/cypress-sendgrid-mailosaur-example repo.
We get this email by filling out the form and retrieving the sent email, and writing the HTML into the Document
1 | // https://github.com/mailosaur/cypress-mailosaur |
There are multiple tests we could write to validate different features of this email. There are codes to confirm, buttons to click, etc. If we let the tests run right now, each test signs up and receives its own email. But we can quickly transform this spec into one email by using cypress-data-session plugin. Just wrap te code in the first beforeEach
hook with cy.dataSession
"setup" method.
1 | // BEFORE |
1 | // AFTER |
Each data session creates a Cypress alias automatically, thus we don't need .its('html.body').as('email')
command. Note the shareAcrossSpecs: true
parameter. It saves the email in the Cypress config process, thus the same email stays cached as long as we need it. Only the very first run of the spec signs up the user and retries the email - all tests afterwards, and even browser spec reloads just fetch the already cached copy. One Mailosaur email = infinite number of tests we can run.
All test runs afterwards simply use the cached HTML email from that data session.
Reusing the cached email is fast. When the first test signs up the user to retrieve the email, it takes about 8 seconds. By reusing the email, the other two tests save 16 seconds. If we reload the specs, all tests use the cached email, and the total spec time drops from 12 to 4 seconds.
Reusing the email is very convenient when working on the tests themselves, as it gives you instant feedback while you are editing the spec source code. Once you are done, you might want to clear the data session cached value to force the full test flow to be tested on each spec run. You can do it by adding the command to the after
hook.
1 | // https://github.com/bahmutov/cypress-data-session |
Note: I wish Cypress team realized that their plugins ecosystem and the ability to show UI controls for plugins is a super power that the test runners have. If I am working with cypress-data-session
plugin, I have to use the browser command log to clear data session by manually calling.
Why can't Cypress allow the plugins to create buttons and labels through an API so that the users could interact with them from the Test Runner? What a missed opportunity.