现在,您的源代码和测试源代码已推送到临时组织,请运行命令以运行 Apex 测试。apex run test
// -------------------------------------------------------------------------
// Run unit tests in test scratch org.
// -------------------------------------------------------------------------
stage('Run Tests In Test Scratch Org') {
rc = command "${toolbelt}/sf apex run test --target-org ciorg --wait 10 --result-format tap --code-coverage --test-level ${TEST_LEVEL}"
if (rc != 0) {
error 'Salesforce unit test run in test scratch org failed.'
}
}
组织授权失败后无法工作 有时,您尝试使用 Salesforce CLI 或 IDE 授权 Dev Hub 组织或临时组织,但未成功登录到该组织。端口对于杂散授权过程保持打开状态,并且您不能使用 CLI 或 IDE。若要继续,请手动结束该过程。
错误:使用者密钥已被获取 假设你在已创建连接应用的组织上运行。当您尝试将检索到的源部署到其他组织时,部署失败并显示错误。发生了什么事?project retrieve startThe consumer key is already taken
CLI 版本信息
使用以下命令可查看有关 Salesforce CLI 的版本信息。
sf plugins --core // Version of the CLI and all installed plug-ins
sf --version // CLI version
错误:未找到默认开发中心
当您尝试创建临时组织时,由于授权问题,您会看到此错误。
假设你使用该标志成功授权了开发人员中心组织。与组织关联的用户名是默认用户名 Dev Hub 用户名。然后,您可以在不使用该标志的情况下成功创建临时组织。但是,当您尝试创建一个临时组织时 再次使用相同的CLI命令时,您会收到以下错误:–set-default-dev-hub–target-dev-hub
Error (1): No default dev hub found. Use -v or --target-dev-hub to specify an environment.
sfdx-project.json has been updated.
Successfully created a package. 0HoB00000004CzHKAU
=== Ids
NAME VALUE
────────── ──────────────────
Package Id 0HoB00000004CzHKAU
更新程序包
要更新名称、描述或用户以接收 现有包,请使用此 命令。
sf package update --package "Expense App" --name "Expense Manager App" \
--description "New Description" --error-notification-username me2@devhub.org
sf package version create report --package-create-request-id 08cxx00000000YDAAY
输出显示有关请求的详细信息。
=== Package Version Create Request
NAME VALUE
───────────────────────────── ────────────────────
Version Create Request Id 08cB00000004CBxIAM
Status InProgress
Package Id 0HoB00000004C9hKAE
Package Version Id 05iB0000000CaaNIAS
Subscriber Package Version Id 04tB0000000NOimIAG
Tag git commit id 08dcfsdf
Branch
CreatedDate 2018-05-08 09:48
Installation URL
https://login.salesforce.com/packaging/installPackage.apexp?p0=04tB0000000NOimIAG
您可以在 的初始输出中找到请求 ID (08c)。sf package version create
sf package version create list --created-last-days 0
显示每个请求的详细信息,如下所示(ID 和标签被截断)。
=== Package Version Create Requests [3]
ID STATUS PACKAGE2 ID PKG2 VERSION ID SUB PKG2 VER ID TAG BRANCH CREATED DATE ===
08c... Error 0Ho...
08c... Success 0Ho... 05i... 04t... 2017-06-22 12:07
08c... Success 0Ho... 05i... 04t... 2017-06-23 14:55
在升级包版本之前,请确保在 Dev 中启用了用户权限“将包版本提升为已发布” 与包关联的中心组织。请考虑使用此用户创建权限集 权限,然后将权限集分配给相应的用户配置文件。
当您准备好发布时,请使用 .sf package version promote
sf package version promote --package "Expense Manager@1.3.0-7"
如果命令成功,则会显示一条确认消息。
Successfully promoted the package version, ID: 04tB0000000719qIAA to released.
更新成功后,查看包详细信息。
sf package version report --package "Expense Manager@1.3.0.7"
确认 Released 属性的值为 。true
=== Package Version
NAME VALUE
────────────────────────────── ───────────────────
Name ver 1.0
Alias Expense Manager-1.0.0.5
Package Version Id 05iB0000000CaahIAC
Package Id 0HoB0000000CabmKAC
Subscriber Package Version Id 04tB0000000NPbBIAW
Version 1.0.0.5
Description update version
Branch
Tag git commit id 08dcfsdf
Released true
Created Date 2018-05-08 09:48
Installation URL
https://login.salesforce.com/packaging/installPackage.apexp?p0=04tB0000000NPbBIAW
sf package install --package "Expense Manager@1.2.0-12" --target-org jdoe@example.com
如果您已使用默认用户名设置了临时组织,请仅输入软件包版本 同上。
sf package install --package "Expense Manager@1.2.0-12"
注意
如果您定义了别名(使用参数),则 可以指定 的别名而不是用户名。-a–target-org
CLI 显示有关安装的状态消息。
Waiting for the subscriber package version install request to get processed. Status = InProgress Successfully installed the subscriber package version: 04txx0000000FIuAAM.
#!/bin/bash
# The execution of this script stops if a command or pipeline has an error.
# For example, failure to install a dependent package will cause the script
# to stop execution.
set -e
# Specify a package version id (starts with 04t)
# If you know the package alias but not the id, use sf package version list to find it.
PACKAGE=04tB0000000NmnHIAS
# Specify the user name of the subscriber org.
USER_NAME=test-bvdfz3m9tqdf@example.com
# Specify the timeout in minutes for package installation.
WAIT_TIME=15
echo "Retrieving dependencies for package Id: "$PACKAGE
# Execute soql query to retrieve package dependencies in json format.
RESULT_JSON=`sf data query -u $USER_NAME -t -q "SELECT Dependencies FROM SubscriberPackageVersion WHERE Id='$PACKAGE'" --json`
# Parse the json string using python to test whether the result json contains a list of ids or not.
DEPENDENCIES=`echo $RESULT_JSON | python -c 'import sys, json; print json.load(sys.stdin)["result"]["records"][0]["Dependencies"]'`
# If the parsed dependencies is None, the package has no dependencies. Otherwise, parse the result into a list of ids.
# Then loop through the ids to install each of the dependent packages.
if [[ "$DEPENDENCIES" != 'None' ]]; then
DEPENDENCIES=`echo $RESULT_JSON | python -c '
import sys, json
ids = json.load(sys.stdin)["result"]["records"][0]["Dependencies"]["ids"]
dependencies = []
for id in ids:
dependencies.append(id["subscriberPackageVersionId"])
print " ".join(dependencies)
'`
echo "The package you are installing depends on these packages (in correct dependency order): "$DEPENDENCIES
for id in $DEPENDENCIES
do
echo "Installing dependent package: "$id
sf package install --package $id -u $USER_NAME -w $WAIT_TIME --publish-wait 10
done
else
echo "The package has no dependencies"
fi
# After processing the dependencies, proceed to install the specified package.
echo "Installing package: "$PACKAGE
sf package install --package $PACKAGE -u $USER_NAME -w $WAIT_TIME --publish-wait 10
exit 0;
如果开发人员中心中有依赖于要传输的包的包,If you have packages in your Dev Hub which depends on the package that you-inter-transfer, 将 sfdx-project.json 文件中的 Package Dependency 部分更新为 显式指定您所依赖的传输包的 04t ID。
已解锁包的包 ID 和别名 在包生命周期中,包和包版本由 ID 或包别名标识。当您创建软件包或软件包版本时,Salesforce CLI 会根据软件包名称创建软件包别名,并将该名称存储在 sfdx-project.json 文件中。运行 CLI 命令或编写脚本以自动执行打包工作流时,通常更容易引用包别名,而不是包 ID 或包版本 ID。
NEXT 将内部版本号递增到下一个可用于包版本的版本号。如果 您不使用 NEXT,并且您也忘记更新版本号 在 sfdx-project.json 文件中,新的包版本使用相同的 number 作为以前的包版本。虽然我们不强制要求包的唯一性 版本号,每个包版本都分配有唯一的订阅者包版本 ID (以 04t 开头)。
// A namespace-visible Apex class
@namespaceAccessible
public class MyClass {
private Boolean bypassFLS;
// A namespace-visible constructor that only allows secure use
@namespaceAccessible
public MyClass() {
bypassFLS = false;
}
// A package private constructor that allows use in trusted contexts,
// but only internal to the package
public MyClass (Boolean bypassFLS) {
this.bypassFLS = bypassFLS;
}
@namespaceAccessible
protected Boolean getBypassFLS() {
return bypassFLS;
}
}
将数据导入 org-needs-data 暂存 组织,通过指定计划定义文件到数据导入 tree 命令。sf data import tree --target-org org-needs-data \ --plan sfdx-out/export-demo-Broker__c-Property__c-plan.json使用参数指定完整路径 命令生成的计划执行文件的名称。计划执行文件名始终以 -plan.json 结尾。–plandata export tree
运行不带标志的 apex run 命令以打开 交互式 shell。在提示符下,输入所有 Apex 代码;完成后按 CTRL-D。 然后,您的代码将在指定组织中的单个执行匿名请求中执行,或者 默认组织(如果未指定)。sf apex run --target-org myscratch此输出显示了执行 Apex 代码的示例system.debug (‘Hello world!’);
Start typing Apex code. Press the Enter key after each line, then press CTRL+D when finished. system.debug (‘Hello world!’); Compiled successfully. Executed successfully.
58.0 APEX_CODE,DEBUG;APEX_PROFILING,INFO Execute Anonymous: system.debug (‘Hello world!’); 14:23:06.174 (174742273)|USER_INFO|[EXTERNAL]|0058H000005QWcE|test-ux9lpg9jyyqt@example.com|(GMT-07:00) Pacific Daylight Time (America/Los_Angeles)|GMT-07:00 14:23:06.174 (174785450)|EXECUTION_STARTED 14:23:06.174 (174792639)|CODE_UNIT_STARTED|[EXTERNAL]|execute_anonymous_apex 14:23:06.174 (175417814)|USER_DEBUG|[1]|DEBUG|Hello world! 14:23:06.175 (175529797)|CUMULATIVE_LIMIT_USAGE 14:23:06.175 (175529797)|LIMIT_USAGE_FOR_NS|(default)| Number of SOQL queries: 0 out of 100 Number of query rows: 0 out of 50000 Number of SOSL queries: 0 out of 20 Number of DML statements: 0 out of 150 Number of Publish Immediate DML: 0 out of 150 Number of DML rows: 0 out of 10000 Maximum CPU time: 0 out of 10000 Maximum heap size: 0 out of 6000000 Number of callouts: 0 out of 100 Number of Email Invocations: 0 out of 10 Number of future calls: 0 out of 50 Number of queueable jobs added to the queue: 0 out of 50 Number of Mobile Apex push calls: 0 out of 10
sf project deploy preview --target-org DevSandbox
No conflicts found.
No files will be deleted.
Will Deploy [2] files.
Type Fullname Path
──────────── ─────────────── ──────────────────────────────────────────────────────────────────────────────
ApexClass WidgetClass force-app/main/default/classes/WidgetClass.cls-meta.xml
CustomObject WidgetObject__c force-app/main/default/objects/WidgetObject__c/WidgetObject__c.object-meta.xml
No files were ignored. Update your .forceignore file if you want to ignore certain files.
sf project retrieve preview --target-org DevSandbox
No conflicts found.
No files will be deleted.
Will Retrieve [3] files.
Type Fullname Path
──────────── ───────────────────────────────── ────
Layout GizmoObject__c-GizmoObject Layout
CustomObject GizmoObject__c
ApexClass GizmoClass
Ignored [2] files. These files won't retrieve because they're ignored by your .forceignore file.
Type Fullname Path
─────── ─────────────────────────────────── ────
Profile Admin
Profile B2B Reordering Portal Buyer Profile
sf project retrieve preview --target-org DevSandbox
No conflicts found.
No files will be deleted.
Will Retrieve [3] files.
Type Fullname Path
──────────── ───────────────────────────────── ────
Layout GizmoObject__c-GizmoObject Layout
CustomObject GizmoObject__c
ApexClass GizmoClass
Ignored [2] files. These files won't retrieve because they're ignored by your .forceignore file.
Type Fullname Path
─────── ─────────────────────────────────── ────
Profile Admin
Profile B2B Reordering Portal Buyer Profile
sf project retrieve preview
No conflicts found.
No files will be deleted.
No files will be retrieved.
Ignored [2] files. These files won't retrieve because they're ignored by your .forceignore file.
Type Fullname Path
─────── ─────────────────────────────────── ────
Profile Admin
Profile B2B Reordering Portal Buyer Profile
现在让我们看一下部署。要预览本地更改,请运行 。project deploy preview
sf project deploy preview --target-org DevSandbox
No conflicts found.
No files will be deleted.
Will Deploy [2] files.
Type Fullname Path
──────────── ─────────────── ──────────────────────────────────────────────────────────────────────────────
ApexClass WidgetClass force-app/main/default/classes/WidgetClass.cls-meta.xml
CustomObject WidgetObject__c force-app/main/default/objects/WidgetObject__c/WidgetObject__c.object-meta.xml
No files were ignored. Update your .forceignore file if you want to ignore certain files.
然后部署本地更改。部署到沙盒后,其他使用 沙盒可以看到您的更改。
sf project deploy start --target-org DevSandbox
Deploying v59.0 metadata to test-ikspctiorkzs@example.com using the v59.0 SOAP API.
Deploy ID: 0Af8D00000pNmKySAK
Status: Succeeded | ████████████████████████████████████████ | 2/2 Components (Errors:0) | 0/0 Tests (Errors:0)
Deployed Source
=====================================================================================================================
| State Name Type Path
| ─────── ─────────────── ──────────── ──────────────────────────────────────────────────────────────────────────────
| Created WidgetClass ApexClass force-app/main/default/classes/WidgetClass.cls
| Created WidgetClass ApexClass force-app/main/default/classes/WidgetClass.cls-meta.xml
| Created WidgetObject__c CustomObject force-app/main/default/objects/WidgetObject__c/WidgetObject__c.object-meta.xml
再次运行。project deploy preview
sf project deploy preview
No conflicts found.
No files will be deleted.
No files will be deployed.
No files were ignored. Update your .forceignore file if you want to ignore certain files.
sf project deploy preview --target-org DevSandbox
Conflicts [1]. Run the command with the --ignore-conflicts flag to override.
Type Fullname Path
───────── ─────────── ───────────────────────────────────────────────────────
ApexClass WidgetClass force-app/main/default/classes/WidgetClass.cls-meta.xml
No files will be deleted.
Will Deploy [1] files.
Type Fullname Path
───────── ────────── ──────────────────────────────────────────────────────
ApexClass GizmoClass force-app/main/default/classes/GizmoClass.cls-meta.xml
No files were ignored. Update your .forceignore file if you want to ignore certain files.
FSCServiceProcess 启用 Financial Service Cloud 的 Service Process Studio 功能。提供 IndustriesServiceExcellenceAddOn 和 FinancialServicesCloudStardardAddOn 许可证各 10 个席位。若要启用该功能,还必须在安装程序中打开 StandardServiceProcess 设置,并授予用户 AccessToServiceProcess 权限。
ServiceCloud 将 Service Cloud 许可证分配给您的临时组织,因此您可以选择客户与您联系的方式,例如通过电子邮件、电话、社交媒体、在线社区、聊天和短信。
ServiceCloudVoicePartnerTelephony 将 Service Cloud Voice with Partner Telephony 附加许可证分配给您的临时组织,以便您可以设置与支持的电话提供商集成的 Service Cloud Voice 联络中心。表示 1–50 之间的值。
ServiceUser 添加一个 Service Cloud 用户许可证,并允许访问 Service Cloud 功能。
SessionIdInLogEnabled 使 Apex 调试日志能够包含会话 ID。如果禁用,则在调试日志中将会话 ID 替换为“SESSION_ID_REMOVED”。
提供对 Einstein Attribution for Marketing Cloud 帐户的访问权限 婚约。Einstein Attribution 使用 AI 建模来动态分配归因百分比 到多个活动接触点。样本临时组织定义文件在启用 Einstein Attribution 之前,请确保将 和 设置为 。enableAIAttributionenableCampaignInfluence2true
同时授权开发人员中心组织和源组织。为每个组织运行此命令。sf auth web login --alias
为源组织创建组织形状。此命令启动一个异步进程,以 创建组织形状。sf org create shape --target-org <source org username/alias> Successfully created org shape for 3SRB0000000TXbnOCG.
检查 shape:create 命令的状态。sf org shape list=== Org Shapes ALIAS USERNAME ORG ID SHAPE STATUS CREATED BY CREATED DATE ────── ──────── ────────────────── ──────────── ────────── ───────────── SrcOrg me@my.org 00DB1230000Ifx5MAC InProgress me@my.org 2020-08-06您可以在状态为 : 之后使用组织形状:Active=== Org Shapes ALIAS USERNAME ORG ID SHAPE STATUS CREATED BY CREATED DATE ────── ───────── ────────────────── ──────────── ──────────── ──────────── SrcOrg me@my.org 00DB1230000Ifx5MAC Active me@my.org 2020-08-06
描述:尽管在源中启用了 DevOps Center org,从源组织的形状创建的临时组织没有 DevOps Center 启用。故意关闭 DevOps Center 组织首选项。我们要求 客户通过在临时中指示功能和设置来显式启用它 出于法律原因的组织定义文件,作为 DevOps Center 条款的一部分,以及 条件。
解决方法:将 DevOps Center 功能和设置添加到 临时组织定义文件。请参阅组织形状的临时组织定义 详。
运行 force:org:shape:list 时出错
描述:从中创建组织形状的试用组织 已过期。您可以看到以下任一错误:
ERROR running org list shape: Error authenticating with the refresh token due to: inactive user
ERROR running org list shape: Error authenticating with the refresh token due to: expired access/refresh token
Required fields are missing: [Welcome Email Template, Change Password Email Template, Lost Password Template]
解决方法:没有。
使用形状创建临时组织时出错
描述:创建临时组织时会看到此错误 使用形状。
ERROR running org create scratch: A fatal signup error occurred. Please try again.
If you still see this error, contact Salesforce Support for assistance.
解决方法:使用命令生成新形状,然后重试。org create shape
使用带字段的形状时,不会填充班次状态选择列表 服务
描述:当您从形状创建临时组织时 启用 Field Service,排班的 状态 字段选择列表为空。
解决方法:使用禁用了现场服务的组织结构,然后 在临时组织定义文件设置中启用 Field Service。
sf org create scratch --definition-file config/project-scratch-def.json --no-track-source
如果临时组织创建成功
执行时,命令 显示有关后台进程的运行信息,例如发送请求、 部署组织设置等。命令完成后,它会显示两个重要的 信息片段:组织 ID 和用户名。org create scratch
Creating Scratch Org...
RequestId: 2SRB000000CSqdEOAT (https://cbdocorg.my.salesforce.com/2SRB000000CSqdEOAT)
OrgId: 00D8I000000PhAk
Username: test-st9thgoyyyq3@example.com
✓ Prepare Request
✓ Send Request
✓ Wait For Org
✓ Available
✓ Authenticate
✓ Deploy Settings
Done
Your scratch org is ready.
您现在可以打开 组织。
sf org open --target-org test-st9thgoyyyq3@example.com
如果使用该标志设置别名,则可以 将该值用于 。–alias–target-org
sf org open --target-org MyScratchOrg
疑难解答提示
如果 create 命令遇到错误,则并不总是清楚临时组织是否 创建。在 Dev Hub 组织上发出此命令,查看它是否返回暂存组织 ID。 这证实了今天创建并由您拥有的临时组织的存在:
sf data query --query "SELECT ID, Name, Status FROM ScratchOrgInfo WHERE CreatedBy.Name = '<your name>' AND CreatedDate = TODAY" --target-org <Dev Hub org>
使用此信息可确定创建是否实际有效。例如,假设 你的名字是 Jane Doe,你为 Dev Hub 组织创建了一个名为 DevHub 的别名:
sf data query --query "SELECT ID, Name, Status FROM ScratchOrgInfo WHERE CreatedBy.Name = 'Jane Doe' AND CreatedDate = TODAY" --target-org DevHub
sf project deploy start
STATE FULL NAME TYPE FILE PATH
──────── ────────────────── ───────── ─────────────────────────────────────────────────────────────────────────────────────────────────────────
Conflict PropertyController ApexClass <dir>/force-app/main/default/classes/PropertyController.cls-meta.xml
Conflict PropertyController ApexClass <dir>/force-app/main/default/classes/PropertyController.cls
Error (1): There are changes in the org that conflict with the local changes you're trying to deploy.
sf project retrieve start
Preparing retrieve request... ⣾ Sending request to org
STATE FULL NAME TYPE FILE PATH
──────── ────────────────── ───────── ───────────────────────────────────────────────────────────────────
Conflict PropertyController ApexClass <dir>force-app/main/default/classes/PropertyController.cls-meta.xml
Preparing retrieve request... Error
Error (1): There are changes in your local files that conflict with the org changes you're trying to retrieve.
sf org create user --set-alias qa-user --target-org my-scratch
Successfully created user "1690397809_test-st9thgoyyyq3@example.com" with ID 0058I002inzvQAA for org 00D80000PhAkUAK.
See more details about this user by running "sf org user display -o 1690397809774_test-st9thgoyyyq3@example.com".
用户与特定的临时组织相关联。指定临时组织用户名或别名 在命令行中带有标志,如果它 尚未设置为默认值。如果尝试为非临时组织创建用户,则该命令将失败。–target-orgorg create user
sf org create user --set-alias qa-user --definition-file config/user-def.json
使用该命令查看与临时组织关联的用户列表。左侧的 (A) 标识 在创建临时组织时创建。org list users
sf org list users --target-org my-scratch
=== Users in org 00D80000PhAkUAK
Default Alias Username Profile Name User Id
─────── ────────── ─────────────────────────────────────────── ──────────────────── ───────────────
(A) my-scratch test-st9thgoyyyq3@example.com System Administrator 0058I002inzvQAA
qa-user 1690397809_test-st9thgoyyyq3@example.com Standard User 0058I002inzvQAA
使用命令显示有关用户的详细信息。org display user
sf org display user --target-org qa-user
Warning: This command exposes sensitive information <truncated for readability>
=== User Description
key label
──────────── ────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Username 1690397809_test-st9thgoyyyq3@example.com
Profile Name Standard User
Id 0058I002inzvQAA
Org Id 00D80000PhAkUAK
Access Token 00D8I<truncated>
Instance Url https://connect-enterprise-1121-dev-ed.scratch.my.salesforce.com
Login Url https://connect-enterprise-1121-dev-ed.scratch.my.salesforce.com
Alias qa-user
查看生成的密码和其他用户详细信息:sf org display user --target-org qa-user Warning: This command exposes sensitive information <truncated for readability> === User Description key label ──────────── ──────────────────────────────────────────────────────────────────────────────────────────────────────────────── Username 1690397809_test-st9thgoyyyq3@example.com Profile Name Standard User Id 0058I002inzvQAA Org Id 00D80000PhAkUAK Access Token 00D8I<truncated> Instance Url https://connect-enterprise-1121-dev-ed.scratch.my.salesforce.com Login Url https://connect-enterprise-1121-dev-ed.scratch.my.salesforce.com Alias qa-user Password ogihymg%lXa
您知道临时组织的实例 URL。如果你不知道,你可以查询你的开发人员 中心组织。为 例:sf data query --target-org my-dev-hub --query "SELECT SignupUsername,LoginUrl FROM ScratchOrgInfo WHERE SignupUsername='test-wvkpnfm5z113@example.com'"
sf org display --target-org my-scratch-org
Warning: This command will expose sensitive information that allows for subsequent activity using your current authenticated session.
Sharing this information is equivalent to logging someone in under the current credential, resulting in unintended access and escalation of privilege.
For additional information, please review the authorization section of the https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_auth_web_flow.htm
=== Org Description
KEY VALUE
─────────────── ────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Access Token <long-string>
Alias my-scratch-org
Api Version 58.0
Client Id PlatformCLI
Created By jdoe@fabdevhub.org
Created Date 2023-06-09T17:59:18.000+0000
Dev Hub Id jdoe@fabdevhub.org
Edition Developer
Expiration Date 2023-06-16
Id 00D8H0000007wprU
Instance Url https://java-connect-41-dev-ed.scratch.my.salesforce.com
Org Name Your Company
Signup Username test-gm9uud@example.com
Status Active
Username test-gm9uud@example.com
启用 Einstein 功能 在开发人员中心打开 Einstein 功能,以消除在临时组织中启用聊天机器人功能的手动步骤。当您接受 Einstein 的服务条款时,从此 Dev Hub 组织创建的每个临时组织都不需要单独接受。如果您之前接受了 Einstein 的服务条款以启用与 Einstein 相关的功能,则此设置已启用。
当您将现有元数据格式转换为源格式时,我们会为 每个位。现在,所有包含 XML 标记的文件都具有 .xml 扩展名,以便 XML 编辑器将它们识别为 XML 文件,您可以查看 他们。要同步本地项目和临时组织,Salesforce DX 项目使用 自定义对象的特定目录结构、自定义对象转换、 Lightning Web 组件、Aura 组件和文档。
例如,如果您有一个名为 Case 的对象,则源格式将提供 XML 版本 称为 Case.object-meta.xml。如果您有一个名为 DreamHouse,我们创建一个名为 DreamHouse.app-meta.xml 的文件。 你明白了。
# Explicilty list the HelloWorld source files to be excluded
helloWorld/main/default/classes/HelloWorld.cls
helloWorld/main/default/classes/HelloWorld.cls-meta.xml
# Exclude the HelloWorld Apex class using an asterisk
helloWorld/main/default/classes/HelloWorld.cls*
排除捆绑包和文件组
使用两个连续的星号 () 忽略文件 分布在多个目录中,只有一个条目。**.forceignore
例如,要排除与名为 的 Lightning Web 组件相关的所有资源文件,请添加此条目以排除整个 组件包:myLwcComponent
# Specify a relative path to a directory from the project root
helloWorld/main/default/classes
# Specify a wildcard directory - any directory named “classes” is excluded
**classes
# Specify file extensions
**.cls*
**.pdf
# Specify a specific file
helloWorld/main/default/HelloWorld.cls*
列出当前被忽略的文件和目录
使用命令列出文件 以及命令当前忽略的项目中的目录。该命令引用文件以确定忽略的文件列表。project list ignoredprojectproject list ignored.forceignore
sf project list ignored --source-dir force-app/main/default
命令找到被忽略的文件时的示例输出:
Found the following ignored files:
force-app/main/default/aura/.eslintrc.json
force-app/main/default/lwc/.eslintrc.json
force-app/main/default/lwc/jsconfig.json
sf alias set my-org test-blahdiblah@example.com
sf alias set my-org test-wvkpnfm5z113@example.com
若要查看已设置的所有别名,请使用以下命令之一。
sf alias list
sf org list
要删除别名,请使用以下命令。alias unset
sf alias unset my-org
列出您的所有组织
使用命令显示用户名和 您已授权的组织和您创建的活动临时组织的别名。org list
sf org list
Type Alias Username Org ID Status Expires
── ─────── ────────────── ───────────────────────────────────────────── ────────────────── ───────────────────── ──────────
D DevHub JulesDevHub jules@sf.com 00DB0001234c7jiMAA Connected
Sandbox jules@sf.com.jssandtwo 00D020012344XTiEAM Connected
O Scratch my-scratch-org test-qjrr9q5d13o8@example.com 00DMN0012342Gez2AE Active 2023-08-21
Legend: D=Default DevHub, O=Default Org Use --all to see expired and deleted scratch orgs
输出列出了已授权或创建的组织,包括开发人员中心组织、 生产组织、临时组织和沙盒。该表显示您的用户名 指定了您何时授权组织、其别名、其 ID 以及 CLI 是否可以 连接到它。左侧的表情符号指向默认组织或 Dev Hub;请参阅 图例在底部了解详情。临时组织还会显示其到期日期。
Jest 是一个强大的工具,具有丰富的功能,可用于编写 JavaScript 测试。使用 Jest 为所有 Lightning Web 组件编写单元测试。
在命令行中运行 Jest 测试,或者在 IDE 中(通过一些配置)运行 Jest 测试。Jest 测试不会在浏览器中运行,也不会连接到组织,因此它们运行速度很快。在“监视模式”下运行时,它们会在您编码时为您提供即时反馈。Jest 测试仅适用于 Lightning Web 组件,不适用于 Aura 组件。
将 Jest 测试编写到:
单独测试组件
测试组件的公共 API(属性和方法、事件)@api
测试基本用户交互(点击次数)
验证组件的 DOM 输出
验证事件是否按预期触发
提示
lwc-recipes 存储库中充满了 Jest 测试。在 的 Lightning Web 组件的文件夹中查找 Jest 测试。__tests__force-app/main/default/lwc
如果安装适用于 Visual Studio Code 的 Salesforce 扩展,则可以在 VS Code 中运行测试、调试测试和监视 Jest 文件。有关详细信息,请参阅适用于 Visual Studio Code 的 Salesforce 扩展。
在命令行上运行测试
要运行项目的所有测试,请使用 Salesforce CLI 命令 sf force lightning lwc test run from your root folder of your project。否则,请运行在安装 Jest 和 dependencies 时添加到项目文件块的命令。scriptspackage.json
npm run test:unit
在开发过程中持续运行测试
若要在每次保存更改时对单个组件运行所有测试,请转到组件目录并运行带有参数的命令。使用您在安装 Jest 和依赖项时添加到项目文件块的条目。sfdx-lwc-jest--watchscriptspackage.json
npm run test:unit:watch
Jest 会监视所有组件文件的更新,并在每次检测到更改时运行所有相关测试。
在调试模式下运行 Jests 测试
如果要逐步执行测试和应用代码,以找出测试或代码未按预期运行的原因,则在调试模式下运行 Jest 测试非常有用。您可以使用以下工具调试 Jest 测试。
VS Code Salesforce 扩展包
Chrome 开发者工具
VS Code 调试器高级配置
VS Code Salesforce 扩展包提供了最简单、最直接的选项,而 Chrome DevTools 则迎合了经验丰富的 Web 开发人员的需求。此外,VS Code 调试器的高级配置使你能够使用不同的调试器和调试方案。高级配置为调试 Jest 测试提供了最灵活的选项。
有关更多信息,请参阅调试 Lightning Web 组件的 Jest 测试。
高级 Jest 配置
sfdx-lwc-jest配置为运行 Jest 测试,无需任何其他更改。但是,如果您是 Jest 的高级用户,请查看 Jest 的其他一些配置选项。请参见 github.com/salesforce/sfdx-lwc-jest#overriding-jest-config。
重要
如果你的 Jest 测试执行缓慢,并且它们有来自不同文件夹的依赖项,请提供映射以加快解析速度。请参阅 lwc-recipes 存储库中的 。moduleNameMapper
调试 Lightning Web 组件的 Jest 测试
VS Code 提供了一些工具来帮助你有效地调试 Jest 测试。根据您的测试要求,使用 Salesforce 扩展包、Chrome DevTools 或 VS Code 调试器高级配置。
Jest 在目录中运行 JavaScript 文件。测试文件的名称必须以 结尾,我们建议测试以 结尾。可以使用一个包含所有组件测试的测试文件,也可以使用多个文件来组织相关测试。测试文件可以放在子文件夹中。__tests__.js.test.js
编写基本测试
要成为一名有成就的测试人员,请学习如何使用 Jest。特别是,学习 Jest 提供的许多匹配器的语法。我们在这里不介绍 Jest 的一般用法,因为 Jest 文档非常出色。我们专注于将 Jest 与 Lightning Web 组件一起使用的细节。
Lightning Web 组件的 Jest 测试应该单独测试单个组件的行为,对外部组件或服务的依赖性最小。
让我们看一下,这是对 lwc-recipes 存储库中 Lightning Web 组件的测试。hello.test.jshello
// hello.test.js
import { createElement } from "lwc";
import Hello from "c/hello";
describe("c-hello", () => {
afterEach(() => {
// The jsdom instance is shared across test cases in a single file so reset the DOM
while (document.body.firstChild) {
document.body.removeChild(document.body.firstChild);
}
});
it("displays greeting", () => {
// Create element
const element = createElement("c-hello", {
is: Hello,
});
document.body.appendChild(element);
// Verify displayed greeting
const div = element.shadowRoot.querySelector("div");
expect(div.textContent).toBe("Hello, World!");
});
});
afterEach(() => {
// The jsdom instance is shared across test cases in a single file so reset the DOM
while (document.body.firstChild) {
document.body.removeChild(document.body.firstChild);
}
});
Jest 还具有其他可用于执行设置和清理任务的方法。请参见 jestjs.io/docs/en/setup-teardown。
const element = createElement("c-hello", {
is: Hello,
});
将测试组件添加到 DOM 中
然后,测试调用以将组件添加到测试的 版本 中。appendChilddocument
调用将组件插入到 DOM 和生命周期钩子中,然后被调用。appendChild()connectedCallback()renderedCallback()
document.body.appendChild(element);
下一步是使用标准的 DOM 查询方法在 DOM 中搜索元素。用作查询的父级。这是一个仅限测试的 API,可让您查看阴影边界以检查组件的阴影树。它等效于 .element.shadowRootthis.template
const div = element.shadowRoot.querySelector("div");
使用断言
最后,该语句是对成功条件的断言:元素的文本为“Hello, World!”expect
const div = element.shadowRoot.querySelector("div");
expect(div.textContent).toBe("Hello, World!");
Jest 支持许多匹配器,例如 和,这使得检查值是否满足条件变得容易。请参见 jestjs.io/docs/en/expect。toBetoMatchObject
测试异步 DOM 更新
当 Lightning Web 组件的状态发生变化时,DOM 会异步更新。若要确保测试在评估结果之前等待更新完成,请返回已解析的 Promise。将测试代码的其余部分链接到解析的 Promise。Jest 等待 Promise 链完成,然后再结束测试。如果 Promise 以拒绝状态结束,则 Jest 无法通过测试。
test("element does not have slds-icon class when bare", () => {
const element = createElement("one-primitive-icon", { is: PrimitiveIcon });
document.body.appendChild(element);
// Property value is assigned after the component is inserted into the DOM
element.variant = "bare";
// Use a promise to wait for asynchronous changes to the DOM
return Promise.resolve().then(() => {
expect(element.classList).not.toContain("slds-icon");
});
});
调用将组件插入到 DOM 和生命周期钩子中,然后被调用。然后,该示例在调用后设置元素值,这类似于在将组件插入 DOM 后由另一个方法或用户交互设置属性的情况。在这些情况下,请使用 promise 等待异步 DOM 更新。有关组件生命周期和呈现的更多信息,请参见生命周期流。appendChild()connectedCallback()renderedCallback()appendChild()
该测试创建组件并将其附加到 DOM。仅当组件连接到 DOM 时,组件才会接收有关数据的更新。组件连接后,将模拟数据传递给电线适配器上的函数。emit
发出模拟数据后,if 或 change 组件将重新呈现。解析 promise 以确保测试代码在 DOM 更新为新数据后运行。该代码验证模拟数据中的产品名称字段是否在 DOM 中正确输出。productname
// productCard.test.js
import { createElement } from "lwc";
import ProductCard from "c/productCard";
import { getRecord } from "lightning/uiRecordApi";
// Import mock data to send through the wire adapter.
const mockGetRecord = require("./data/getRecord.json");
test("displays product name field", () => {
const element = createElement("c-product_filter", { is: ProductCard });
document.body.appendChild(element);
// Emit mock record into the wired field
getRecord.emit(mockGetRecord);
// Resolve a promise to wait for a rerender of the new content.
return Promise.resolve().then(() => {
const content = element.shadowRoot.querySelector(".content");
const nameField = mockGetRecord.fields.Name.value;
expect(content.textContent).toBe(`Name:${nameField}`);
});
});
注意
在 Spring ’21 及更早版本中,您必须注册正在测试的电线适配器。该代码仍然有效,但不建议这样做。
Lightning Web 组件基于 Web 组件标准。该标准包括 Shadow DOM,它对其他组件隐藏组件的标记、样式和行为。这种封装给 UI 测试带来了挑战,尤其是依赖于全局搜索 DOM 或进入自定义元素内部的测试。
该属性封装元素的 DOM 子树。这在 DOM 中表示为 一个。 这个 DOM 子树中的元素不能通过传统的 DOM 查询方法获得。由 Lightning Web 组件呈现的元素包含此新属性,并且这些元素在正常的 DOM 查询中是隐藏的。shadowRootshadowRootDocumentFragmentshadowRoot
我们建议使用 Jest 对单个 Lightning Web 组件进行单元测试。
仅将 Selenium WebDriver 等 UI 测试工具用于端到端测试。
开玩笑测试
要为 Lightning Web 组件编写单元测试,请使用 sfdx-lwc-jest。
在 Jest 测试上下文中,代码可以使用被测元素的属性来访问影子树。该属性封装元素的影子树。shadowRootshadowRoot
此代码在“示例”部分访问组件的影子树。<div><lightning-lwc-parent>
const element = createElement("c-lightning-lwc-parent", { is: LightningLwcParent });
document.body.appendChild(element);
const div = element.shadowRoot.querySelector(".in-the-shadow");
正如本文所讨论的,全局查询通过失败。要在 Lightning Web 组件的影子树中查找元素,请在客户端上执行 JavaScript 以查询组件的属性。WebDriver.findElement()shadowRoot
注意
本文有一个屏幕截图,显示了 Chrome 开发者工具中的 DOM 元素。屏幕截图显示了一个文档片段,它是组件影子树的顶部节点。如果您在 Chrome 开发者工具中查看 Lightning Web 组件,则看不到 因为 LWC 使用影子 DOM polyfill。Salesforce 支持某些未实现 Shadow DOM Web 标准的浏览器。polyfill 在这些浏览器中提供了一个影子 DOM。要在页面上查找 Lightning Web 组件,请查找包含连字符的元素名称。选择元素并在控制台中运行。Lightning Web 组件返回 .#shadow-root#shadow-root$0.shadowRoot#document-fragment
Jest 测试模式和模拟依赖关系
在使用 Jest 进行测试时,请遵循这些模式和做法来隔离行为并最大限度地提高单元测试的效率。
测试属性更改
让我们从一个简单的属性更改开始。属性更改时的组件重新渲染是异步的,因此向 DOM 添加某些内容的顺序并不总是可预测的。我们建议您在检查预期行为之前,等待值更改反映在 DOM 中。一种技术使用语句在页面元素更改后检查值,如下所示:Promise.resolve()
在 Jest 测试中,我们使用 jest-transformer 将 import 语句转换为变量声明。该值设置为标签路径。默认情况下,分配的字符串值为 。您可以使用为导入提供自己的值。此示例返回字符串而不是 。@salesforce/labelmyImportc.specialLabeljest.mock()value set in testc.specialLabel
import myImport from "@salesforce/label/c.specialLabel";
jest.mock(
"@salesforce/label/c.specialLabel",
() => {
return { default: "value set in test" };
},
{ virtual: true },
);
寻找更多示例?
请参阅 lwc-recipes 存储库的 lwc 目录。许多食谱都有一个目录,其中包含注释的 jest tests。__tests__