Cookie 在 supertest/superagent 测试中持续存在,但用户未保持登录状态
Cookies persist in supertest/superagent test, but the user doesn't stay logged in
我的目标
我试图开玩笑地使用 supertest 的 agent
函数 beforeEach()
在每次测试之前登录用户,因为我希望每个测试都 运行 假设用户已登录。为了进行身份验证,我使用的是 passport 和 passport-local。
这是我尝试过的(为简洁起见删除了部分):
测试文件:
import { agent, SuperAgentTest } from 'supertest';
import app from '../../src/app';
// create a `testRequest` variable to use in the tests
// that will be refreshed in between
let testRequest: SuperAgentTest;
const fakeUser = { email: 'john@john', username: 'john', password: 'john' };
beforeEach(async () => {
// create new agent
testRequest = agent(app);
// register and login
await testRequest.post('/register').send(fakeUser).expect(302);
// other irrelevant stuff...
});
// protected route
describe('POST /campgrounds/new', () => {
it('returns 200 OK', () => {
return testRequest.get('/campgrounds/new');
})
});
/register
路线:
router.post('/register', async (req, res) => {
const { password, ...details } = req.body;
try {
// I am using passport-local-mongoose for this function-
// it just registers the user
const user = await User.register(new User(details), password);
req.login(user, (err) => {
// error handling and redirect
});
} catch (e) {
// error handling
}
})
这是我的结果
我得到的不是 200 状态,而是 302 状态,这意味着我被重定向到登录页面。为了调试它,我创建了一个名为 /current
的测试路由,它将记录当前用户和会话 ID cookie。然后我分别在 it
和 beforeEach
函数中向这条路由发送了一个 GET
请求。
有趣的是,它们都记录了相同的会话 ID,但只有 beforeEach
中的请求附加了一个用户对象。
#1 确保正文解析器顺序正确
确保在任何路由或与身份验证相关的事情之前有这个。
app.use(express.json())
#2 检查 Passport 中间件连接
确保在任何 app.use('/', aRouter)
、router.get
、router.post
等之前调用 app.use(passport.initialize())
和 app.use(passport.session())
:
// Set up session w/ specific config
app.use(session({
secret: 'bquyqueajhbd',
resave: true,
saveUninitialized: true,
store: new FileStore({path: '/tmp/session'})
}));
// Wire up the
app.use(passport.initialize())
app.use(passport.session())
编辑:关于 req.user
的注释
Passport 被设计用来在会话中存储用户 ID。
对服务器的每个请求都必须从数据库重新加载用户。
这是中间件 passport.initialize()
和 passport.session()
.
的工作
那里的逻辑将调用 passport.deserializeUser
通过 ID 查找用户 - 与 passport.serializeUser
登录会话时保存的 ID 相同。
passport.serializeUser(function(user, done) {
done(null, user.id); // <-- Here's where the ID is saved to session.
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user); // <-- Here is where the `req.user` get's it's value from.
});
});
To debug this I'd focus on the passport.deserializeUser
callback, add logs before and after the DB query.
(注意:我已经有几年没教这个了。如果我没有使用精确的术语等,请见谅)
我的目标
我试图开玩笑地使用 supertest 的 agent
函数 beforeEach()
在每次测试之前登录用户,因为我希望每个测试都 运行 假设用户已登录。为了进行身份验证,我使用的是 passport 和 passport-local。
这是我尝试过的(为简洁起见删除了部分):
测试文件:
import { agent, SuperAgentTest } from 'supertest';
import app from '../../src/app';
// create a `testRequest` variable to use in the tests
// that will be refreshed in between
let testRequest: SuperAgentTest;
const fakeUser = { email: 'john@john', username: 'john', password: 'john' };
beforeEach(async () => {
// create new agent
testRequest = agent(app);
// register and login
await testRequest.post('/register').send(fakeUser).expect(302);
// other irrelevant stuff...
});
// protected route
describe('POST /campgrounds/new', () => {
it('returns 200 OK', () => {
return testRequest.get('/campgrounds/new');
})
});
/register
路线:
router.post('/register', async (req, res) => {
const { password, ...details } = req.body;
try {
// I am using passport-local-mongoose for this function-
// it just registers the user
const user = await User.register(new User(details), password);
req.login(user, (err) => {
// error handling and redirect
});
} catch (e) {
// error handling
}
})
这是我的结果
我得到的不是 200 状态,而是 302 状态,这意味着我被重定向到登录页面。为了调试它,我创建了一个名为 /current
的测试路由,它将记录当前用户和会话 ID cookie。然后我分别在 it
和 beforeEach
函数中向这条路由发送了一个 GET
请求。
有趣的是,它们都记录了相同的会话 ID,但只有 beforeEach
中的请求附加了一个用户对象。
#1 确保正文解析器顺序正确
确保在任何路由或与身份验证相关的事情之前有这个。
app.use(express.json())
#2 检查 Passport 中间件连接
确保在任何 app.use('/', aRouter)
、router.get
、router.post
等之前调用 app.use(passport.initialize())
和 app.use(passport.session())
:
// Set up session w/ specific config
app.use(session({
secret: 'bquyqueajhbd',
resave: true,
saveUninitialized: true,
store: new FileStore({path: '/tmp/session'})
}));
// Wire up the
app.use(passport.initialize())
app.use(passport.session())
编辑:关于 req.user
的注释
Passport 被设计用来在会话中存储用户 ID。
对服务器的每个请求都必须从数据库重新加载用户。
这是中间件 passport.initialize()
和 passport.session()
.
那里的逻辑将调用 passport.deserializeUser
通过 ID 查找用户 - 与 passport.serializeUser
登录会话时保存的 ID 相同。
passport.serializeUser(function(user, done) {
done(null, user.id); // <-- Here's where the ID is saved to session.
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user); // <-- Here is where the `req.user` get's it's value from.
});
});
To debug this I'd focus on the
passport.deserializeUser
callback, add logs before and after the DB query.
(注意:我已经有几年没教这个了。如果我没有使用精确的术语等,请见谅)