许多类在使用配置对象创建(实例化)时使用简写名称。简写名称称为别名
(如果类扩展了 Ext.Component,则称为xtype
)。别名/xtype 列在适用类的类名旁边,以便快速参考。
框架类或其成员可以指定为private
或protected
。否则,该类/成员为public
。Public
、protected
和private
是访问描述符,用于传达类或类成员的使用方式和时间。
Public 类和类成员可供任何其他类或应用程序代码使用,并且可以作为主要产品版本中稳定且持久的成员。公共类和成员可以通过子类安全地扩展。
Protected 类成员是稳定的public
成员,旨在供拥有类或其子类使用。受保护的成员可以通过子类安全地扩展。
Private 类和类成员由框架内部使用,不打算供应用程序开发人员使用。私有类和成员可能会在任何时候更改或从框架中省略,恕不另行通知,并且不应在应用程序逻辑中依赖它们。
static
标签。*请参阅下面的静态。以下是一个示例类成员,我们可以对其进行分解以显示类成员的语法(在本例中,从 Ext.button.Button 类中查看的 lookupComponent 方法)。
让我们看看成员行中的每个部分
lookupComponent
)( item )
)Ext.Component
)。对于不返回任何内容(除了 undefined
)的方法,这可能会被省略,或者可能显示为用正斜杠 /
分隔的多个可能值,表示返回的内容可能取决于方法调用的结果(例如,如果 get 方法调用成功,方法可能会返回一个组件,如果失败则返回 false
,这将显示为 Ext.Component/Boolean
)。PROTECTED
- 请参阅下面的标志部分)Ext.container.Container
)。如果成员来自当前类,则源类将显示为蓝色链接,如果它从祖先类或混合类继承,则显示为灰色。查看源代码
)item : Object
)。undefined
,则“返回值”部分将记录返回的类或对象的类型以及描述(在本例中为 Ext.Component
)。自 3.4.0 起可用
- 示例中未显示),紧接在成员描述之后。默认值为:false
)。API 文档使用许多标志来进一步传达类成员的功能和意图。标签可以用文本标签、缩写或图标表示。
classInstance.method1().method2().etc();
false
,则标记为可阻止的事件将不会触发。- 表示框架类
- 单例框架类。*有关更多信息,请参阅单例标志
- 组件类型框架类(Ext JS 框架中任何扩展 Ext.Component 的类)
- 表示该类、成员或指南在当前查看的版本中是新的
- 表示类型为 config
的类成员
- 表示类型为 property
的类成员
- 表示类型为 method
的类成员
- 表示类型为 event
的类成员
- 表示类型为 theme variable
的类成员
- 表示类型为 theme mixin
的类成员
- 表示该类、成员或指南在当前查看的版本中是新的
在 API 文档页面上的类名称下方,有一排按钮,对应于当前类拥有的成员类型。每个按钮都显示了按类型划分的成员数量(此数量会随着应用过滤器而更新)。单击按钮将导航到该成员部分。将鼠标悬停在成员类型按钮上将显示一个弹出菜单,其中包含该类型的所有成员,以便快速导航。
与类配置选项相关的 Getter 和 Setter 方法将显示在方法部分以及 API 文档和成员类型菜单的配置部分中,位于它们所使用的配置下方。Getter 和 Setter 方法文档将在配置行中找到,以便于参考。
您的页面历史记录保存在本地存储中,并在顶部标题栏下方显示(使用可用的空间)。默认情况下,仅显示与您当前查看的产品/版本匹配的页面搜索结果。您可以通过单击历史记录栏右侧的 按钮并选择“全部”单选按钮来扩展显示的内容。这将显示所有产品/版本的历史记录栏中的所有最近页面。
在历史记录配置菜单中,您还会看到最近页面访问的列表。结果按“当前产品/版本”和“全部”单选按钮进行过滤。单击 按钮将清除历史记录栏以及本地存储中保存的历史记录。
如果在历史记录配置菜单中选择了“全部”,则“在历史记录栏中显示产品详细信息”的复选框选项将被启用。选中后,每个历史页面的产品/版本将与历史记录栏中的页面名称一起显示。将鼠标悬停在历史记录栏中的页面名称上也会显示产品/版本作为工具提示。
可以使用页面顶部的搜索字段搜索 API 文档和指南。
在 API 文档页面上,还有一个过滤器输入字段,使用过滤器字符串过滤成员行。除了按字符串过滤外,还可以按访问级别、继承和只读来过滤类成员。这是使用页面顶部的复选框完成的。
API 类导航树底部的复选框过滤类列表,以包含或排除私有类。
单击空搜索字段将显示您最近的 10 次搜索,以便快速导航。
每个 API 文档页面(除了 Javascript 原语页面)都具有与该类相关的元数据的菜单视图。此元数据视图将具有以下一项或多项
Ext.button.Button
类具有 Ext.Button
的备用类名称)。备用类名称通常为了向后兼容而维护。默认情况下,可运行示例(Fiddle)会在页面上展开。您可以使用代码块左上角的箭头,单独折叠和展开示例代码块。您也可以使用页面右上角的切换按钮,切换所有示例的折叠状态。切换所有状态将在页面加载之间保存。
默认情况下,类成员在页面上是折叠的。您可以使用成员行左侧的箭头图标展开和折叠成员,或者使用右上角的展开/折叠所有切换按钮全局操作。
在较窄的屏幕或浏览器上查看文档,将显示针对较小外形尺寸优化的视图。桌面视图和“移动”视图之间的主要区别在于
可以通过单击 API 文档页面顶部的类名来查看类源代码。可以通过单击成员行右侧的“查看源代码”链接来查看类成员的源代码。
在 Sencha Test 中编写的测试将分为以下类别
单元测试
功能测试
了解如何利用每种类型的测试的优势,将确保应用程序具有最高程度的完整性。
单元测试可以描述为针对应用程序底层代码的测试。这种类型的测试可能对应用程序开发人员特别感兴趣。
功能测试分析运行中的应用程序,而不是仅仅测试其各个部分。
这种类型的测试可能对质量保证和最终用户特别感兴趣。
让我们通过说明单元测试可以在不启动应用程序的情况下执行,而功能测试则需要启动应用程序才能执行测试,来澄清这种概括性的描述。
这种区别很重要,因为 Sencha Test 以及 Ext JS 5+ 可以测试代码,而无需任何 UI 存在。例如,您可以在没有运行应用程序的情况下测试数据模型中的验证。应用程序中使用的视图也可以独立于应用程序进行测试。
通过运行中的应用程序进行测试时,应用程序的许多方面可能难以或耗时地进行测试。测试可能要求您首先遵循一组特定的导航步骤,或者以特定用户类型的身份登录。
例如,考虑一个场景,您想要测试“用户”可以编辑给定字段,而“管理员”角色可以在“用户详细信息”面板上编辑。功能测试要求您启动应用程序并以用户身份登录,而不是以管理员身份登录。然后,也许导航到“用户列表”视图,从列表中选择一个用户,然后单击编辑按钮以启动“用户详细信息”弹出窗口。然后,您需要评估“用户”有资格编辑的字段。
最终,我们只想了解“用户”是否可以编辑“用户详细信息”类型视图中的某些字段。使用单元测试,只需创建一个测试,该测试只启动注入“用户”权限的视图。然后,您可以根据权限评估字段的可编辑性。
在探索功能测试之前,让我们先看看一些常见的单元测试用例,以及如何在 Sencha Studio 中执行这些测试。
注意:单元测试不需要应用程序或 Sencha 框架。也就是说,我们遵循此模型来创建一个从头到尾的指南路径。
对于这个单元测试,让我们测试一下 User
模型的验证。我们要确保代表输入用户数据的 data stub 在我们的参数范围内是有效的。
首先,让我们通过添加以下文件将 User
模型类添加到我们的应用程序中:"{appName}/app/model/User.js"
Ext.define('MyApp.model.User', {
extend: 'Ext.data.Model',
fields: ['first', 'last', 'fullname', 'username'],
validators: {
first: 'presence',
last: { type: 'length', min: 2 },
username: [
{ type: 'exclusion', list: ['Admin', 'Operator'] },
{ type: 'format', matcher: /([a-z]+)[0-9]{2,3}/i }
]
}
});
现在可以实例化“User”模型以进行测试。接下来,让我们在场景中添加一些数据,以便测试在验证我们的 User 模型时能够访问这些数据。我们将在工作区根目录中创建一个文件夹/文件:"{workspaceRoot}/shared/userdata.js"。 "userdata" 文件将包含以下内容
var __my_user_data = {
first: 'Rick',
last: 'Grimes',
username: 'rgrimes'
}
接下来,我们将“userdata”文件添加到测试项目中,以便任何场景的测试都可以访问它。为此,请单击测试项目“Additional Libraries”标题下的“+ Add”按钮,双击默认字段值,单击文件夹图标以调出文件选择器,然后从“[workspaceRoot]/shared”目录中选择“userdata.js”文件。最后,单击顶部工具栏中的“Save”按钮。
在接下来的步骤中,我们将创建用于验证“userdata”值是否通过我们的“User”模型类验证的单元测试。
首先,通过单击“Test Project”视图中“Scenarios”标题下的“+ Add”按钮来创建一个场景。为了便于本指南的说明,我们将它命名为“User Data”。
接下来,右键单击工作区导航树中的“User Data”节点,选择“New > Jasmine Test Suite”,并将用户验证测试命名为“UserValidation”。这将把“UserValidation”测试添加为“User Data”场景的子项。
单击工作区验证树中的“UserValidation.js”节点以打开测试编辑器视图。
最后,用以下内容替换占位符测试脚本
describe("UserValidation", function() {
it("should pass", function(done) {
Ext.require('MyApplication.model.User', function () {
var user = new MyApplication.model.User(__my_user_data),
failedValidation = user.getValidation().dirty;
expect(failedValidation).toBe(!true);
done();
});
});
});
在这个测试中,我们期望模型验证示例用户数据。如果您在场景的测试运行器中运行测试,您应该会看到它确实通过了!
除了测试非视图逻辑之外,我们还可以对我们更大应用程序的各个部分进行单元测试,以确保它们正常工作。在这个测试中,让我们创建一个带有徽章的按钮,该徽章显示在按钮的 badgeText
配置中设置的文本。
首先,将以下文件夹/文件添加到您的应用程序中:"{workspaceRoot}/app/view/button/BadgeButton.js"
Ext.define('MyApplication.view.button.BadgeButton', {
extend: 'Ext.button.Button',
xtype: 'badgebutton',
config: {
badgeText: null
},
childEls: ['badgeEl'],
cls: 'da-badge-button',
hideBadgeOnDisabled: true,
initRenderData: function() {
return Ext.apply(this.callParent(), {
badgeText: this.badgeText
});
},
updateBadgeText: function(text) {
var me = this;
if (me.rendered) {
me.badgeEl.setHtml(text).setVisible(text);
} else {
me.on('render', function() {
me.badgeEl.setVisibilityMode(Ext.dom.Element.DISPLAY);
me.badgeEl.setHtml(text).setVisible(text);
});
}
},
onDisable: function() {
this.callParent();
if (this.hideBadgeOnDisabled) {
this.badgeEl.hide();
}
},
onEnable: function() {
this.callParent();
this.badgeEl.show();
}
}, function(BadgeButton) {
BadgeButton.prototype.renderTpl += '<span id="{id}-badgeEl" class="da-badgeElCls" data-ref="badgeEl">{badgeText}</span>';
});
接下来,在我们的应用程序的测试项目中创建一个名为“Badge Button”的新场景,然后右键单击该场景以创建一个名为“ButtonText”的新 Jasmine Test Suite。
我们可以在徽章按钮测试套件中添加一个 describe()
,其中包含多个 it()
规范。每个 it()
的描述将显示为“ButtonText”下场景测试树中的节点。
在“ButtonText”选项卡中输入以下测试。这将允许 Studio 评估徽章文本,并确保在按钮被禁用时徽章元素被隐藏。
describe("ButtonText", function() {
var btn;
beforeEach(function(){
btn = Ext.create('MyApplication.view.button.BadgeButton', {
renderTo: Ext.getBody()
});
});
afterEach(function () {
btn.destroy();
});
it("should have a badge of 2", function() {
btn.setBadgeText('update');
expect(btn.badgeEl.getHtml()).toBe('update');
});
it("badge should be hidden", function() {
btn.setBadgeText('update');
btn.disable();
expect(btn.badgeEl.isVisible()).toBe(false);
});
});
运行测试应该在“ButtonText”中显示两个规范的绿色勾号。
单元测试敏捷,允许对内部代码和隔离的组件进行离散测试。单元测试在防御应用程序演变和变得更加复杂时引入的错误方面提供了一条强大的防线。但是,功能测试在错误防御策略中也占有一席之地,不应被完全放弃而只依赖单元测试。
一套单元测试全部通过是完全有可能的,这会让你相信你的应用程序已经防错。然而,只有当你运行应用程序时,你才会发现应用程序环境中的一些动态元素在单元测试中没有被捕获。
对于某些操作,唯一实用的方法是启动应用程序并对其进行测试。
一个例子是在应用程序中导航视图之间。
假设您的应用程序有一个父容器,其中包含一个卡片视图和两个子视图:主页和用户列表。
然后,假设您想测试当 URL 包含 #!/user/rgrimes
时,路由是否正常工作以显示特定用户的详细信息视图。
在内部,您在父视图的 viewController 中有一个路由,它根据 #!/user/
路由到用户面板,用户面板的 viewController 使用哈希的 /rgrimes
部分打开用户详细信息面板。测试这种类型的导航逻辑正是功能测试发挥作用的地方。应用程序的启动负责呈现主容器及其子容器,进而启动它们各自的 viewController 来管理视图之间的路由逻辑。
复杂路由是您想要从 Studio 启动应用程序并运行测试逻辑以验证应用程序功能的一种场景。另一个可能需要使用功能测试的原因是测试在真实环境中运行的应用程序。
想象一下,您已经设置了一个单元测试来确保“用户详细信息”视图可以被“用户”查看,但可以被“主管”和“管理员”编辑。您有一个单元测试来确保“每周概述”在用户查看时显示单个用户的详细信息,但在主管查看时显示整个团队的汇总信息。
配置用户角色的“管理员仪表板”仅对管理员可见,而对主管和用户不可见。有了所有这些单元测试,您可能会认为所有方面都已涵盖,并且应用程序的每个独特方面都已测试过,因此您可以部署。现在想象一下,用户启动应用程序,但无法登录,因为与服务器/数据库的连接断开。从远程服务器提取用户角色信息的函数测试本可以在应用程序部署之前解决此问题。
单元测试和功能测试在保护您的应用程序免受错误方面至关重要。
幸运的是,Sencha Test 为您提供了管理和执行这两者的工具。本指南提供了一些单元测试的简单示例,但随着您构建测试基础,您将需要包含更多内容,而不仅仅是直接逻辑测试。您将需要模拟 UI 中的用户交互。
要了解如何轻松地将模拟的用户交互添加到您的单元/功能测试中,请查看 事件记录器指南。