About ui5-best-practices-qunit
A skill for writing, reviewing, and modernizing UI5 QUnit tests. It provides rules for async tests, test setup and cleanup, Sinon usage, and code style.
Key features
- 01Guidance for new QUnit tests
- 02Modernization and review rules
- 03Async test patterns
- 04Sinon sandbox and bridge guidance
- 05Setup and cleanup requirements
- 06ESLint and style checklist
Use cases
- 01Creating a UI5 QUnit test module
- 02Refactoring tests during a QUnit 2 migration
- 03Reviewing async test behavior
Install
Copy the command and run it in a terminal.
$
npx skills add https:/ / github.com/ ui5/ plugins-coding-agents --skill ui5-best-practices-qunitAfter installing, type/ui5-best-practices-qunitin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
references/async-patterns.mdmodernizing-tests.mdwriting-new-tests.mdDetails
From the project READMEQUnit Test Best Practices for UI5
When to load each reference
| Trigger | Load |
|---|---|
| Writing a new QUnit test file or module from scratch | references/writing-new-tests.md |
| Modernizing, refactoring, or reviewing existing test code | references/modernizing-tests.md |
Migrating from QUnit 1 (globals: test, asyncTest, ok, stop, start) to QUnit 2 | references/modernizing-tests.md |
Any test touches nextUIUpdate, Core.applyChanges, assert.async, fake timers, or event-based async | references/async-patterns.md |
Load the reference before producing any output. Do not work from memory.
Core rules (always apply)
| Rule | Detail |
|---|---|
No var | Use const or let. One declaration per line - no comma chains. |
No .bind(this) | Use arrow functions for callbacks that do not need their own this. |
assert.expect(N) in every async test | Guards against silent passes when async callbacks never fire. Not required for sync tests. |
sinon.createSandbox() | sinon.sandbox.create() emits a runtime deprecation warning in Sinon 5+ - prefer sinon.createSandbox(). Alternatively use the QUnit-sinon bridge (this.stub(), this.spy(), this.mock(); this.clock only when sinon.config.useFakeTimers is truthy). Do not mix both approaches in the same module. |
| Descriptive test names | Sentence describing behavior. Never start with "it should". Unique within each module. |
beforeEach / afterEach in every module | Create all controls in beforeEach, destroy them in afterEach. No shared mutable state between tests. |
try/finally in helper-created controls | Helpers that create a control must destroy it in finally so it is cleaned up even when assertions throw. |
| No non-ASCII characters | No non-ASCII characters in comments, strings, or JSDoc. Use plain ASCII hyphens, not em dashes. UTF-8 is required, but non-ASCII in comments has historically caused encoding issues. |
| ESLint - 0 errors | Warnings for pre-existing patterns (max-nested-callbacks, no-use-before-define, valid-jsdoc) are acceptable. |
Quick-reference checklist
Use when authoring or reviewing a QUnit test file:
- No
var- useconstorlet; one declaration per line (no comma chains) - No
.bind(this)- use arrow functions for callbacks that do not need their ownthis - No
assert.async()in simple cases - useasync function+await new Promise(...) - Every
asynctest hasassert.expect(N) - No
sinon.sandbox.create()in new code - usesinon.createSandbox()or the bridge (this.stub(),this.spy(),this.mock());this.clockonly when fake timers are enabled - No
"it should..."test titles - use descriptive sentences - Every
QUnit.modulehasbeforeEach/afterEachthat create and destroy all controls - With fake timers: prefer
await nextUIUpdate(this.clock)overCore.applyChanges(); only keepCore.applyChanges()whennextUIUpdate(clock)cannot handle the case - Helper functions that create controls destroy them in
try/finally - No non-ASCII characters in comments or strings (UTF-8 required, but non-ASCII causes encoding issues)
Comments
Markdown supported