赛普拉斯在自定义命令中加载环境变量
Cypress load environment variables in custom commands
我正在构建一个 Next.js 应用程序并使用 Cypress 编写我的测试。我在本地使用 .env.local
file 配置环境变量。在 CI 管道中,它们被正常定义。
我正在尝试在 Cypress 中编写一个自定义命令来加密 cypress/support/command.ts
中的会话。
import { encryptSession } from 'utils/sessions';
Cypress.Commands.add(
'loginWithCookie',
({
issuer = 'some-issuer',
publicAddress = 'some-address',
email = 'some-mail',
} = {}) => {
const session = { issuer, publicAddress, email };
return encryptSession(session).then(token => {
cy.setCookie('my-session-token', token);
return session;
});
},
);
当这个命令运行时,它失败了,因为 encryptSession
使用了一个 TOKEN_SECRET
环境变量,Cypress 不会加载。
import Iron from '@hapi/iron';
const TOKEN_SECRET = process.env.TOKEN_SECRET || '';
export function encryptSession(session: Record<string, unknown>) {
return Iron.seal(session, TOKEN_SECRET, Iron.defaults);
}
我怎样才能让赛普拉斯从那个文件加载环境变量,如果它在那里(=仅在本地,因为变量是在 CI 中定义的 - 它应该正常检测管道中的其他变量,所以相当于检测一个已经用 export MY_VAR=foo
)?
设置的变量
有Cypress.env,但您想在process.env
上设置令牌,这看起来与Cypress版本不完全一致。
我知道任何带有前缀为 CYPRESS_ 的键的 process.env
最终会在 Cypress.env()
中结束,但您想朝相反的方向前进。
我会使用一个任务让你访问文件系统和process.env
,
/cypress/plugins/index.js
module.exports = (on, config) => {
on('task', {
checkEnvToken :() => {
const contents = fs.readFileSync('.env.local', 'utf8'); // get the whole file
const envVars = contents.split('\n').filter(v => v); // split by lines
// and remove blanks
envVars.forEach(v => {
const [key, value] = v.trim().split('='); // split the kv pair
if (!process.env[key]) { // check if already set in CI
process.env[key] = value;
}
})
return null; // required for a task
},
})
在任何测试之前调用任务,可以在 /cypress/support/index.js 或 before()
中,也可以在自定义命令中。
在自定义命令中
Cypress.Commands.add(
'loginWithCookie',
({
issuer = 'some-issuer',
publicAddress = 'some-address',
email = 'some-mail',
} = {}) => {
cy.task('checkEnvToken').then(() => { // wait for task to finish
const session = { issuer, publicAddress, email };
return encryptSession(session).then(token => {
cy.setCookie('my-session-token', token);
return session;
});
})
});
深入研究 @hapi/iron
的代码,有一个对 crypto
的调用,它是一个 Node 库,因此您可能需要将整个 encryptSession(session)
调用移动到一个任务中让它工作。
import { encryptSession } from 'utils/sessions';
module.exports = (on, config) => {
on('task', {
encryptSession: (session) => {
const contents = fs.readFileSync('.env.local', 'utf8'); // get the whole file
const envVars = contents.split('\n').filter(v => v); // split by lines
// and remove blanks
envVars.forEach(v => {
const [key, value] = v.trim().split('='); // split the kv pair
if (!process.env[key]) { // check if already set in CI
process.env[key] = value;
}
})
return encryptSession(session); // return the token
},
})
与
通话
cy.task('encryptSession', { issuer, publicAddress, email })
.then(token => {
cy.setCookie('my-session-token', token);
});
哪里去运行上面的cy.task
我想你只需要在每个测试会话中 运行 它一次(这样它就可以为许多规范文件设置)在这种情况下调用它的地方在 before()
中/cypress/support/index.js.
将它放在那里的缺点是有点隐藏,所以我个人会把它放在每个规范文件顶部的 before()
中。
fs.readFileSync
中的时间开销很小,但与等待页面加载等相比是最小的。
Steve 的回答实际上帮助我在 cypress/plugins/index.ts
中得到了这段代码。
import dotenv from 'dotenv';
dotenv.config({ path: '.env.local' });
import { encryptSession } from 'utils/sessions';
/**
* @type {Cypress.PluginConfig}
*/
const pluginConfig: Cypress.PluginConfig = (on, config) => {
on('task', {
encryptSession: (session: {
issuer: string;
publicAddress: string;
email: string;
}) => encryptSession(session),
});
};
export default pluginConfig;
然后在cypress/support/commands.ts
.
Cypress.Commands.add(
'loginWithCookie',
({
issuer = 'some-issuer',
publicAddress = 'some-address',
email = 'some-email',
} = {}) => {
const session = { issuer, publicAddress, email };
return cy.task<string>('encryptSession', session).then(token => {
return cy.setCookie('my-secret-token', token).then(() => {
return session;
});
});
},
);
我正在构建一个 Next.js 应用程序并使用 Cypress 编写我的测试。我在本地使用 .env.local
file 配置环境变量。在 CI 管道中,它们被正常定义。
我正在尝试在 Cypress 中编写一个自定义命令来加密 cypress/support/command.ts
中的会话。
import { encryptSession } from 'utils/sessions';
Cypress.Commands.add(
'loginWithCookie',
({
issuer = 'some-issuer',
publicAddress = 'some-address',
email = 'some-mail',
} = {}) => {
const session = { issuer, publicAddress, email };
return encryptSession(session).then(token => {
cy.setCookie('my-session-token', token);
return session;
});
},
);
当这个命令运行时,它失败了,因为 encryptSession
使用了一个 TOKEN_SECRET
环境变量,Cypress 不会加载。
import Iron from '@hapi/iron';
const TOKEN_SECRET = process.env.TOKEN_SECRET || '';
export function encryptSession(session: Record<string, unknown>) {
return Iron.seal(session, TOKEN_SECRET, Iron.defaults);
}
我怎样才能让赛普拉斯从那个文件加载环境变量,如果它在那里(=仅在本地,因为变量是在 CI 中定义的 - 它应该正常检测管道中的其他变量,所以相当于检测一个已经用 export MY_VAR=foo
)?
有Cypress.env,但您想在process.env
上设置令牌,这看起来与Cypress版本不完全一致。
我知道任何带有前缀为 CYPRESS_ 的键的 process.env
最终会在 Cypress.env()
中结束,但您想朝相反的方向前进。
我会使用一个任务让你访问文件系统和process.env
,
/cypress/plugins/index.js
module.exports = (on, config) => {
on('task', {
checkEnvToken :() => {
const contents = fs.readFileSync('.env.local', 'utf8'); // get the whole file
const envVars = contents.split('\n').filter(v => v); // split by lines
// and remove blanks
envVars.forEach(v => {
const [key, value] = v.trim().split('='); // split the kv pair
if (!process.env[key]) { // check if already set in CI
process.env[key] = value;
}
})
return null; // required for a task
},
})
在任何测试之前调用任务,可以在 /cypress/support/index.js 或 before()
中,也可以在自定义命令中。
在自定义命令中
Cypress.Commands.add(
'loginWithCookie',
({
issuer = 'some-issuer',
publicAddress = 'some-address',
email = 'some-mail',
} = {}) => {
cy.task('checkEnvToken').then(() => { // wait for task to finish
const session = { issuer, publicAddress, email };
return encryptSession(session).then(token => {
cy.setCookie('my-session-token', token);
return session;
});
})
});
深入研究 @hapi/iron
的代码,有一个对 crypto
的调用,它是一个 Node 库,因此您可能需要将整个 encryptSession(session)
调用移动到一个任务中让它工作。
import { encryptSession } from 'utils/sessions';
module.exports = (on, config) => {
on('task', {
encryptSession: (session) => {
const contents = fs.readFileSync('.env.local', 'utf8'); // get the whole file
const envVars = contents.split('\n').filter(v => v); // split by lines
// and remove blanks
envVars.forEach(v => {
const [key, value] = v.trim().split('='); // split the kv pair
if (!process.env[key]) { // check if already set in CI
process.env[key] = value;
}
})
return encryptSession(session); // return the token
},
})
与
通话cy.task('encryptSession', { issuer, publicAddress, email })
.then(token => {
cy.setCookie('my-session-token', token);
});
哪里去运行上面的cy.task
我想你只需要在每个测试会话中 运行 它一次(这样它就可以为许多规范文件设置)在这种情况下调用它的地方在 before()
中/cypress/support/index.js.
将它放在那里的缺点是有点隐藏,所以我个人会把它放在每个规范文件顶部的 before()
中。
fs.readFileSync
中的时间开销很小,但与等待页面加载等相比是最小的。
Steve 的回答实际上帮助我在 cypress/plugins/index.ts
中得到了这段代码。
import dotenv from 'dotenv';
dotenv.config({ path: '.env.local' });
import { encryptSession } from 'utils/sessions';
/**
* @type {Cypress.PluginConfig}
*/
const pluginConfig: Cypress.PluginConfig = (on, config) => {
on('task', {
encryptSession: (session: {
issuer: string;
publicAddress: string;
email: string;
}) => encryptSession(session),
});
};
export default pluginConfig;
然后在cypress/support/commands.ts
.
Cypress.Commands.add(
'loginWithCookie',
({
issuer = 'some-issuer',
publicAddress = 'some-address',
email = 'some-email',
} = {}) => {
const session = { issuer, publicAddress, email };
return cy.task<string>('encryptSession', session).then(token => {
return cy.setCookie('my-secret-token', token).then(() => {
return session;
});
});
},
);