Materialize 贡献指南:从 Issue 报告到 Jasmine 测试的完整开源协作实践
2026/9/18 21:08:19 网站建设 项目流程

Materialize 贡献指南:从 Issue 报告到 Jasmine 测试的完整开源协作实践

【免费下载链接】materializeMaterialize, a CSS Framework based on Material Design项目地址: https://gitcode.com/gh_mirrors/ma/materialize

本篇指南以 Materialize(一个基于 Material Design 的 CSS 框架)仓库根目录下的 CONTRIBUTING.md 为核心,系统梳理了参与该开源项目的完整协作路径:如何使用 Issue 追踪器高效报告 Bug 与功能请求、如何提交合格的 Pull Request、如何翻译文档,以及如何基于 Jasmine 与 Grunt 编写组件测试。读者读完本文后,将能掌握一套可直接套用的开源贡献工作流,并理解sass/js/jade/tests/等目录在代码库中的角色分工。

引言:贡献流程的基本约定

在开始任何贡献之前,请先通读 CONTRIBUTING.md 全文。这份文档的核心目的是让整个贡献过程对各方都高效、顺畅:遵循规范意味着你尊重维护者与其他贡献者的时间,维护者也会以同样的尊重对待你的 Issue 与补丁。

在深入仓库之前,文档给出了几个出发点:项目聊天室、官方网站与社交媒体账号。从仓库本身看,Materialize 的代码结构大致可分为:

  • sass/ —— 框架样式源码,入口为 materialize.scss;
  • js/ —— 组件 JavaScript 源码(如 dropdown.js、toasts.js);
  • jade/ —— 官方文档页面模板源码;
  • tests/spec/ —— 基于 Jasmine 的组件测试;
  • Gruntfile.js —— 构建、编译与测试的任务编排。

使用 Issue 追踪器

Issue 追踪器是提交Bug 报告、功能请求和 Pull Request的首选渠道,但需要遵守以下硬性约定:

  • 不要把追踪器当作个人技术支持渠道;个人问题应前往 Stack Overflow 的materialize标签或 Gitter 频道提问;
  • 不要发布 “+1”“👍” 之类的无意义评论,请使用 GitHub 的 reactions 功能,维护者保留删除违规评论的权利;
  • 不要在未清晰陈述问题与期望结果的情况下直接开 Issue;
  • 务必在开新 Issue 前搜索重复或已关闭的 Issue,并浏览标签列表,重复 Issue 会被直接关闭;
  • 问题解决后请自行关闭自己的 Issue;
  • 每位参与者都应遵守CODE_OF_CONDUCT.md,保持礼貌与尊重。

标签体系:component:*与状态标签

仓库的 Bug 追踪器使用多类标签来组织和标识 Issue,含义如下:

标签含义
component:*每个组件都有对应标签,为问题涉及的组件添加相应标签
confirmed已用精简测试用例复现、确认为 Materialize 缺陷的问题
css源自编译后 CSS 或 Sass 源码的问题
js源自编译后或源码 JavaScript 的问题
docs用于改进或更新文档的问题
help-wanted需要社区协助解决的问题
meta与项目本身或仓库相关的问题
on-hold应处理但暂时不会作为 PR 被接受的问题或 PR

Bug 报告:三条核心准则

一个 Bug 是仓库代码导致的可演示问题。优秀的 Bug 报告极具价值,而含糊不清的 Issue 会被关闭。提交前请遵循:

  1. 先搜索—— 检查该问题是否已被报告;
  2. 确认是否已修复—— 尝试用最新master或开发分支复现;
  3. 隔离问题—— 使用项目提供的 Codepen 模板创建一个精简测试用例(reduced test case)。

一份好的 Bug 报告应包含足够细节,不让别人反复追问:你的运行环境是什么?复现步骤是什么?受影响的浏览器与操作系统?其他浏览器表现是否不同?你期望的结果是什么?填写 Issue 模板即可覆盖这些信息。

功能请求与代码示例

  • 功能请求需符合项目目标而非个人需求,并尽可能给出示例与细节;若请求的是 Material Design 指南 中的组件,请附上组件链接。
  • 凡是适用的 Issue 都必须附带 Codepen 演示,否则会被关闭或忽略。

Pull Request:提交与审查全流程

好的 PR(补丁、改进、新功能)极具价值,但文档特别强调了两点前置约定:

  • 先询问再动手:任何重大 PR 前请先与维护者沟通,否则可能白费大量时间;
  • 不要直接编辑materialize.cssmaterialize.js:这些是自动生成的产物,应修改 sass/ 与 js/ 下的源文件。

这一约定在 Gruntfile.js 中可以得到印证:发布任务release会通过sassconcatbabeluglifypostcss等任务从源码生成dist/产物,例如concat:dist将 js/ 下包括cash.jscomponent.jsglobal.js在内的全部组件模块拼接为temp/js/materialize.js,再经 Babel 转换得到dist/js/materialize.js。直接改动产物文件会在下一次构建时被覆盖。

文档类贡献:改对地方

为 Materialize 文档做贡献时,应编辑master 分支下 jade/page-contents/ 中的文档源码文件,不要编辑gh-pages分支——该分支由文档源码生成,由维护者单独管理。这一结构同样体现在 Gruntfile.js 的jade任务中:它把 jade/ 下每个.jade页面(如jade/buttons.jadejade/modals.jade)编译为对应的 HTML 页面。

提交 PR 的标准流程

  1. Fork 并配置远程仓库

    # 克隆你自己的 fork 到当前目录 git clone https://github.com/<your-username>/materialize.git # 进入新克隆的目录 cd materialize # 将原仓库关联为名为 upstream 的远程仓库 git remote add upstream https://github.com/Dogfalo/materialize.git
  2. 同步最新变更

    git checkout master git pull upstream master
  3. 创建主题分支(基于主开发分支,用于承载你的功能、改动或修复):

    git checkout -b <topic-branch-name>
  4. 分逻辑块提交,Commit Message 用英文书写,遵循规范的 Git 提交信息指南,否则代码很难被合并进主项目;

  5. 合并(或 rebase)upstream 开发分支到你的主题分支

    git pull [--rebase] upstream master
  6. 推送主题分支到你的 fork

    git push origin <topic-branch-name>
  7. 针对master分支打开 Pull Request:标题与描述要清晰,在描述中引用相关 Issue 以便自动关联;保持提交历史干净简洁。提交后 CI(Travis CI)会自动运行测试并显示通过标记,随后维护者会审查代码并给出反馈,全部通过后即可合并。

翻译贡献

如果你希望帮助把文档翻译成其他语言,可发送邮件说明想加入的语言团队。项目使用 Transifex 作为本地化平台,加入后会收到平台邀请。

Jasmine 测试指南

测试是 PR 能否被合并的关键保障。Materialize 使用Jasmine作为测试框架,并集成了 jQuery 以支持用 jQuery 语法编写测试。以下内容结合 CONTRIBUTING.md 与仓库实际代码展开。

参考与前置准备

官方参考资料包括:Jasmine 官方文档、Grunt Jasmine 插件、仓库中的示例测试 tests/spec/ 以及 Travis CI。

开始前请安装 grunt 及其全部依赖。验证依赖是否齐全的方式是运行:

grunt travis

它会在你没有做任何改动时报错时,提示你依赖安装不完整。从 Gruntfile.js 末尾的travis任务定义可以看到,该命令实际执行三个环节:

grunt.registerTask('travis', ['js_compile', 'sass_compile', 'jasmine']);

即先编译 JS(concat+babel)、编译 Sass,再运行 Jasmine 测试;测试配置通过jasmine.components目标指定了:

  • src: ['bin/materialize.js']—— 被测的打包产物;
  • vendor—— jQuery 与 jasmine-jquery 依赖;
  • styles: 'bin/materialize.css'—— 被测样式;
  • specs: 'tests/spec/**/*Spec.js'—— 测试用例文件;
  • helpers: 'tests/spec/helper.js'—— 测试辅助脚本。

相关依赖与脚本命令同样记录在 package.json 中("test": "grunt travis""dev": "grunt monitor")。

测试目录结构约定

每个组件应有自己的独立目录,并遵循现有测试的命名约定。仓库 tests/spec/ 下的目录与文件完整呈现了这一约定,例如:

  • tests/spec/toast/toastSpec.js
  • tests/spec/dropdown/dropdownSpec.js 与配套的 dropdownFixture.html
  • tests/spec/helper.js

其中每个*Fixture.html文件是 jasmine-jquery 的 DOM 夹具,*Spec.js是对应组件的测试描述。写测试前,请确保你基于 fork 的一个干净分支工作,这会大幅简化 PR 流程。

编写测试:describe / it / expect 的正确姿势

写测试前,先真正理解组件的预期行为——通读组件源码与文档会大有帮助。测试结构上:

  • describe块划分测试区间,用it块将每个区间进一步细分为功能点;
  • it块内可以写多条 expect 断言;
  • 一般原则是同时测试正向用例与反向用例,以降低误报概率。

仓库中的真实示例 tests/spec/toast/toastSpec.js:

it('Opens a toast with HTML content', function() { var $toastContent = $('<span>I am toast content</span>'); M.toast({html: $toastContent, displayLength: 400}); toast = $('.toast'); expect(toast.first('span').text()).toBe('I am toast content'); expect(toast.first('span').text()).not.toBe('I am toast'); });
  • beforeEachafterEach可分别用于每个用例执行前后设置场景或重置状态;
  • 编写 expect 断言时,务必写清期望行为描述字符串,这样测试失败时能立刻看出问题所在:
expect(toast.length).toBe(0, 'because toast should be removed by now');

当断言失败时,原因信息 “because toast should be removed by now” 会直接展示出来。

由于组件是重度前端交互的,需要熟悉用 jQuery 方式操作 DOM 与组件,例如用trigger模拟用户点击等事件。tests/spec/helper.js 中预置了window.clickwindow.mouseenterwindow.keydown等事件派发辅助函数,正是为了这一目的;而 tests/spec/dropdown/dropdownSpec.js 展示了如何通过loadFixtures('dropdown/dropdownFixture.html')加载 DOM 夹具,再断言toBeHidden/toBeVisible

测试 CSS 属性比较困难,需要发挥创造力保证样式仍正常工作;尽量覆盖更多用例,个别边界情况不必过度担心,可以用 TODO 注释说明有问题的边界场景,让维护者知晓。

两个实用的 Jasmine 技巧

  1. 只跑指定用例:用--filter参数,例如:

    grunt travis --filter=tabs

    该命令只会运行名称中包含tabs的 spec。

  2. 异步测试与超时:测试中需要等待动画或异步动作时,必须使用done回调——在it()的匿名函数中声明done参数,随后可正常使用 JavaScript 的window.setTimeout,测试完成时调用done()

    it ('should wait for a timeout', function(done) { // Execute action timeout(setTimeout(function() { // Wait a second // Test for result done(); }, 1000); });

    注意:一旦声明了done回调却从不调用done(),测试会永远挂起,并在约 5 秒后超时报错。仓库中 tests/spec/toast/toastSpec.js 的 “should display and remove a toast” 用例就是嵌套setTimeout+done()的典型示范,它依次断言 Toast 出现、持续存在、最终被移除,并通过源码中定义的toastInDuration(300ms)与toastOutDuration(375ms,见 js/toasts.js 的_defaults)计算等待时间。

从测试反观组件实现

理解测试规范后,可以顺带从源码印证测试为何如此设计。以 js/toasts.js 为例,其_defaults定义了 Toast 的全部可配置参数:htmldisplayLength(默认 4000ms)、inDuration(300ms)、outDuration(375ms)、classescompleteCallbackactivationPercent(0.8,用于拖动关闭的激活阈值)。M.toast()会在页面没有 Toast 容器时自动创建#toast-container,并注册鼠标与触摸的拖动事件——这正是测试中用M.toast({...})驱动、并断言.toast元素行为的基础。类似的,js/global.js 中的M.initializeJqueryWrapper将每个组件类包装为jQuery.fn插件(如$('.dropdown-trigger').dropdown('open')),Component基类(js/component.js)则统一处理实例的创建、销毁与批量初始化——测试中的 jQuery 调用方式即源于此。

许可证约定

重要:通过贡献代码,你即同意项目所有者按照 LICENSE(MIT License)的条款对你的工作成果进行许可。这是参与本项目的基本法律前提。

结语

从 Issue 规范、标签体系,到 PR 提交流程、文档编辑边界,再到 Jasmine 测试的编写技巧,这份贡献指南为每一位参与者划定了清晰、可执行的路径。将它与 tests/spec/ 中的真实测试、js/ 与 sass/ 的源码结构、以及 Gruntfile.js 的grunt travis构建链对照阅读,你就能以维护者期望的方式高效地提交高质量贡献。

【免费下载链接】materializeMaterialize, a CSS Framework based on Material Design项目地址: https://gitcode.com/gh_mirrors/ma/materialize

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询