无密码的身份验证越来越流行。 这是具有身份验证功能的一种简单方法。拥有魔术链接的主要优点是更好的安全性。一个密码以减少用户重复使用密码。此外,您确保用户通过电子邮件确认其帐户。
使用电子邮件身份验证的痛点是测试。不再了!
比赛表
这篇文章的灵感来自于我的项目https://happyreact.com/的工作。在产品文档中添加一个反馈小部件。制造更好的产品,避免用户流失并推动更多销售!
让我们开始
我们将使用电子邮件提供商打开的NextAuth.js自举。对于我们的测试,这将是一个很棒且易于使用的操场。
标题中所述,我们的测试框架将是Playwright。我在项目中使用它,它具有出色的开发人员经验。
补充软件包:
-
smtp-tester用于启动SMTP本地服务器
-
cheerio用于在电子邮件html中找到链接
-
nodemailer用于发送电子邮件
我配置了电子邮件提供商并添加了Playwright。无非是遵循剧作家和NextAuth电子邮件适配器设置的标准安装。 关注the next auth email provider guide关于如何设置它。
tl; dr;
安装这些软件包:
yarn add smtp-tester cheerio --dev
导入SMTP-TESTER和CHEERIO:
import { test } from '@playwright/test';
import smtpTester from 'smtp-tester';
import { load as cheerioLoad } from 'cheerio';
您的测试应该看起来像这样:
test.describe('authenticated', () => {
let mailServer;
test.beforeAll(() => {
mailServer = smtpTester.init(4025);
});
test.afterAll(() => {
mailServer.stop();
});
test('login to app', async ({ page, context }) => {
await page.goto('/login');
// your login page test logic
await page
.locator('input[name="email"]')
.type('test@example.com', { delay: 100 });
await page.locator('text=Request magic link').click({ delay: 100 });
await page.waitForSelector(
`text=Check your e-mail inbox for further instructions`
);
let emailLink = null;
try {
const { email } = await mailServer.captureOne('test@example.com', {
wait: 1000
});
const $ = cheerioLoad(email.html);
emailLink = $('#magic-link').attr('href');
} catch (cause) {
console.error(
'No message delivered to test@example.com in 1 second.',
cause
);
}
expect(emailLink).not.toBeFalsy();
const res = await page.goto(emailLink);
expect(res?.url()?.endsWith('/dashboard')).toBeTruthy();
await context.storageState({
path: path.resolve('tests', 'test-results', 'state.json')
});
}
});
通过我们创建的服务器发送电子邮件:
// This check will work when you pass NODE_ENV with 'test' value
// when running your e2e tests
const transport = process.env.NODE_ENV === 'test'
? nodemailer.createTransport({ port: 4025 })
: nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT,
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASSWORD
}
});
â!â!!
,请确保通过此SMTP服务器发送电子邮件设置电子邮件提供商
在这一点上,我认为您已经设置了一个SMTP提供商,并且您熟悉此事。 当您需要指南时,请在我的博客上查看How to set up an SMTP provider for testing。
让我们进行身份验证的测试。创建Authenticated.spec.ts在我们的测试目录中使用一个空描述块中的文件。我们想使用beforeall和eather hook。
// authenticated.spec.ts
import { test } from '@playwright/test';
test.describe('authenticated', () => {
test.beforeAll(() => {});
test.afterAll(() => {});
})
接下来,安装SMTP-TESTER软件包并将其导入到我们创建的测试中。运行以下命令:
yarn add smtp-tester cheerio --dev
并添加启动/停止SMTP服务器
import { test } from '@playwright/test';
import smtpTester from 'smtp-tester';
import { load as cheerioLoad } from 'cheerio';
test.describe('authenticated', () => {
let mailServer: any;
test.beforeAll(() => {
mailServer = smtpTester.init(4025);
});
test.afterAll(() => {
mailServer.stop();
});
});
这里发生了什么?
-
在所有测试之前,我们是启动SMTP服务器
-
毕竟测试,我们正在停止此服务
重要的部分是我们正在端口 4025 上创建SMTP服务器。我们稍后将使用此端口发送电子邮件。
测试登录表格
现在,让我们写一些测试逻辑。您应该在某些操作后将文本调整为您在应用程序中显示的内容。 HappyReact文本如下。
// authenticated.spec.ts
test('login to app', async ({ page, context }) => {
await page.goto('/login');
// your login page test logic
await page
.locator('input[name="email"]')
.type('test@example.com', { delay: 100 });
await page.locator('text=Request magic link').click({ delay: 100 });
await page.waitForSelector(
`text=Check your e-mail inbox for further instructions`
);
let emailLink = null as any;
try {
const { email } = await mailServer.captureOne('test@example.com', {
wait: 1000
});
const $ = cheerioLoad(email.html);
emailLink = $('#magic-link').attr('href');
} catch (cause) {
console.error(
'No message delivered to test@example.com in 1 second.',
cause
);
}
expect(emailLink).not.toBeFalsy();
const res = await page.goto(emailLink);
expect(res?.url()?.endsWith('/dashboard')).toBeTruthy();
await context.storageState({
path: path.resolve('tests', 'test-results', 'state.json')
});
}
这里发生了什么?
-
转到登录页面并填写我们的电子邮件地址
-
捕获发送到我们的电子邮件地址的电子邮件
-
将电子邮件从电子邮件加载到Cheerio中并找到登录链接
-
检查链接是否存在并访问
-
保存验证cookies以后在测试(可选)
中使用它们
ðâ€是一个好主意,将ID添加到电子邮件模板中的URL链接。这将使您发现它更容易。
还记得我们的SMTP服务器在端口4025上运行吗? 我们需要指示NodeMailer使用此服务器而不是标准服务器发送电子邮件。是捕获测试中的电子邮件并防止其发送到真实电子邮件地址的唯一方法。确保您仅在测试中使用它。
// This check will work when you pass NODE_ENV with 'test' value
// when running your e2e tests
const transport = process.env.NODE_ENV === 'test'
? nodemailer.createTransport({ port: 4025 })
: nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT,
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASSWORD
}
});
â!â!!
,请确保通过此SMTP服务器发送电子邮件包起来
测试发送电子邮件总是很痛苦。该技术可以扩展。除了身份验证外,您还可以测试其他功能,例如发票或团队邀请。结果更好的应用程序。