Style Guide
ESTABLISHING CODE STYLE STANDARDS AND CONVENTIONS FOR ALL PROJECTS
1. INTRODUCTION AND LEGAL FRAMEWORK
Section titled “1. INTRODUCTION AND LEGAL FRAMEWORK”1.1. Policy Overview
Section titled “1.1. Policy Overview”This Style Guide (hereinafter referred to as “the Guide”) establishes mandatory code style standards, conventions, and formatting requirements applicable to all projects maintained by our organisation. This Guide operates within our comprehensive legal and policy framework, incorporating our Terms of Service, Contributor Covenant, and all applicable legal protections by reference.
1.2. Scope and Applicability
Section titled “1.2. Scope and Applicability”This Guide applies to all code contributions to SpellWare-maintained repositories, regardless of contributor status. All contributors to our projects are required to comply with the standards set forth in this Guide.
IMPORTANT: Non-compliance with this Guide may result in rejection of contributions, requests for modification, or other appropriate actions as determined by project maintainers.
Note for Mentorship Programme Participants: This Guide governs contributions to SpellWare-maintained repositories only. It does not apply to your flagship project. Your flagship project is your own intellectual property, and you are entirely free to set your own style standards, choose your own licence, and use your own copyright attribution.
1.3. Legal Compliance and Intellectual Property
Section titled “1.3. Legal Compliance and Intellectual Property”All code contributions must comply with:
- Our global software licence: Naomi’s Public Licence
- Contributor Covenant requirements
- Applicable intellectual property laws and regulations
- Export control and data protection requirements
2. GLOBAL CONVENTIONS
Section titled “2. GLOBAL CONVENTIONS”These sections apply to all code in any of our projects.
2.1. Copyright Notice
Section titled “2.1. Copyright Notice”All code files should begin with a comment section containing the copyright information:
/** * @copyright SpellWare * @license Naomi's Public License * @author Naomi Carrigan */Note that copyright must be assigned to SpellWare, and our license must be applied, but when checking in new code you may attribute yourself as the author, or add yourself to the list for existing code.
3. JAVASCRIPT AND TYPESCRIPT PROJECTS
Section titled “3. JAVASCRIPT AND TYPESCRIPT PROJECTS”The following sections apply to our JavaScript/TypeScript projects. Style conventions are enforced through our custom ESLint package.
3.1. Main Rules
Section titled “3.1. Main Rules”These rules apply to all TypeScript code, and will run on files in src/**/*.ts.
3.1.1. ESLint Enforced Rules
Section titled “3.1.1. ESLint Enforced Rules”- Setters must have a corresponding getter.
- Array methods which return a value must return a value in the callback.
- Arrow functions should always use curly braces.
- Variables must be used within the scope they are defined.
- Comments should always start with a capital letter.
- Avoid overly complex functions.
returnstatements must either never return a value, or always return a value.ifstatements and similar control blocks should always use curly braces.- Switch statements must always have a default case, and the default case must always come last.
- Never use loose equality.
- A
forloop’s iteration direction must match the conditional bound. - Functions assigned to a property must match the name of the property.
- With the exception of callback functions, all functions should be assigned a name.
- When using the
functionkeyword, preferfunction name()declarations overconst name = function()expressions. - Getters should always return a value.
- Getters and setters should be grouped together.
- You should never use logical assignment operators.
- You should never have more than one class per file.
- Logical blocks should not be nested more than five levels deep. Prefer extracting into separate functions.
- Files should not have more than 300 lines. Prefer extracting into modular functions.
- Functions should not have more than 50 lines. Prefer breaking down into smaller logic.
- Callbacks should not be nested more than two levels.
- Functions should not have more than 20 logical statements/branches.
- Constructor names should begin with a capital letter.
- Do not use the
alertAPI. - Promise executor functions should not be async.
- Do not use
awaitwithin loops. - Do not use bitwise operators.
- Do not use
arguments.callerorarguments.callee. - Do not declare variables within switch case statements.
- Do not reassign class definitions.
- Do not compare with
-0. - Do not perform assignments in conditions e.g.
if (name = "Naomi"). - Do not use the
consoleAPI, prefer our custom logger. - Avoid confusing operator combinations e.g.
a + b ?? c. - Avoid constant conditions e.g.
if(false)orwhile(true). - Constructors should not return a value. They implicitly return the instance.
- Do not use control characters
\x00in regular expressions. - Do not use
debuggerstatements. - Do not use
deleteon variables. - Do not start a regular expression with
=(confusing with/=operator). - Functions should not have multiple parameters with the same name.
- Classes should not have multiple members with the same name.
- Objects should not have multiple keys with the same name.
- If/else statements should not use the same condition.
- Switch statements should not have duplicate case conditions.
- Import statements should not have duplicate imports.
- Prefer using early return over if/else.
- Block statements should not be empty.
- Character classes in regular expressions should not be empty.
- Destructured values should not be empty.
- Static class blocks should not be empty.
- You should not use loose equality with
null. - You should not use
eval. - Do not reassign the error parameter in a catch block.
- Do not extend native prototypes.
- Do not call
bindunnecessarily. - Do not cast to a boolean in conditions.
- Do not use
continueorbreakunnecessarily. - All case statements should have a break statement.
- Do not reassign function declarations.
- Do not reassign global values (e.g.
window). - Do not use implicit coercion (e.g.
!!bool,+num). - Do not declare global variables. All values should be scoped to a module.
- Do not reassign to imported variables.
- Do not declare functions in logical blocks.
- Do not pass invalid regular expression strings to
RegExp(). - Do not use
thisoutside of classes. - Do not use unusual space characters.
- Do not access
__iterator__. - Do not use loop labels.
- Do not create unnecessary blocks.
- Do not nest
ifwithinelse, useelse if. - Do not use multi-code characters (such as emotes) within character classes.
- Do not chain assignment operators.
- Do not use
\to create multi-line strings. Use concatenation or template strings. ifconditions should not be in the negative (e.g.!bool).- Do not nest ternary statements.
- Do not use
newoutside of an assignment. - Do not use
newwithBigIntorSymbol. - Do not use
newwithString,Number, orBoolean. - Do not use octal escapes (e.g.
\8,\2). - Do not call the
Math,JSON,Reflect,Atomics, orIntlobjects as functions or constructors. - Do not call
new Object()without an argument. - Do not use octal literals e.g.
071. - Do not reassign function parameters.
- Do not use the
++operator. - Do not use
returnin promise executors. - Do not use the
__proto__property. - Prefer calling the Object prototype over builtins (e.g.
Object.prototype.hasOwnProperty.call(foo, "bar")overfoo.hasOwnProperty("bar")). - Do not use literal spaces in regular expressions, use the escape sequence
\s. - Do not return assignment operations.
- Do not use
javascript:voidURLs. - Do not assign a variable to itself.
- Do not compare a variable with itself.
- Do not use the comma operator to evaluate multiple expressions.
- Setters should not return a value.
- Do not allow sparse arrays.
- Do not use
${foo}template interpolation in regular strings. - Do not reference
thisbefore callingsuperin constructors that callsuper. - Do not reference variables that are not declared.
- Do not initialise variables to
undefined. - With the exception of trailing underscores for unused variables, do not use dangling underscores.
- Do not insert line breaks in confusing locations, such as the middle of a variable assignment.
- Do not use a variable in a loop condition that is not modified within the loop.
- Do not use a ternary if a simpler approach exists.
- There should be no unreachable code.
- Do not use control statements in
finallyblocks. - You must use parentheses when negating
inorinstanceof, e.g.if (!(key in obj)). - Do not use optional chaining where an undefined value is not allowed.
- Do not declare private class members that are not consumed by the class.
- Do not declare variables that are unused.
- Avoid backreferences in regular expressions when they would match nothing.
- Do not use
.call()or.apply()unnecessarily. catchstatements should handle an error, not turn around and throw the error.- Do not use computed-key syntax for literal keys e.g.
{["a"]: "b"}. - Do not concatenate string literals without variables.
- Do not escape characters unnecessarily.
- Do not rename a reference to the same name e.g.
let { a: a } = b;. - Do not use redundant
returnstatements. - No use of the
varkeyword. - Do not merge
TODOorFIXcomments into the main branch. - Do not use the
withstatement. - An object must use either all long-form definitions
{a : a}or all short-form definitions{ a }, but never a mix of the two{ a, b: c}. - Avoid shorthand operators
+=, prefer the explicitx = x + y. - Callback functions should be anonymous arrow functions.
- Use
constfor all variables that are not reassigned. - Capture groups should be named.
- Prefer
Object.hasOwn(). - Prefer the spread operator over
Object.assign. - Prefer regular expression literals over the RegExp constructor.
- Prefer using the
...operator instead ofarguments. - Prefer the spread operator over
.apply(). - Prefer template literals over string concatenation.
parseInt()should always be given a radix.- When an asynchronous function relies on an argument that might change (such as an object reference), care must be taken to avoid race conditions within that function.
- Generator functions must use the
yieldkeyword. - Object keys must be sorted alphabetically.
- Variables within the same declaration block must be sorted alphabetically.
- If using the
Symbolfunction, you must include a description. - Do not compare to
NaN, useNumber.isNaN(). typeofcomparators must be a valid return type oftypeof.- Conditions should always start with the variable, not the constant.
3.1.2. TypeScript-ESLint Enforced Rules
Section titled “3.1.2. TypeScript-ESLint Enforced Rules”- Do not use
awaiton functions that do not return a Promise. - Exported type definitions should use the
export typekeyword. - Use dot notation for property access, unless such syntax would be invalid.
- Do not use the
deletekeyword with arrays. - Do not use
<Object>.toString()on objects. PreferJSON.stringify(). - Do not assign void values to variables, such as
const log = console.log("Bad");. - Do not duplicate types (e.g.
type myType = "A" | "A"). - Promises should always be awaited.
- Do not implicitly evaluate code, such as with
new Function(). - Do not use
voidwith functions that do not return a value. - Do not use Promises in places that do not consume them (such as callbacks).
- Do not combine string and number values in an enum.
- Do not use unions/intersections with overriding values (such as
anyorunknown). - Do not use comparison operators with boolean values (e.g.
variable === false). - Do not pass values to a conditional statement that are always truthy or falsy.
- Do not use unnecessary namespace references.
- Do not use template strings without interpolated values.
- Do not pass type arguments to a function that match the default value of that parameter.
- Do not define unused type parameters in a function.
- Values with an
anytype should not be passed to function calls. - Values with an
anytype should not be assigned to variables. - Values which have an
anytype should not be called as functions. - Do not merge declarations (instead of
interface Fooandclass Foo, useinterface Fooandclass Bar implements Foo). - Do not compare enum values against arbitrary values.
- Do not use the
Functiontype. Functions should have a specific type signature. - Values with an
anytype cannot have properties, and such properties should not be accessed. - Functions should not return an
anyvalue. - The unary minus operator should only be used on numbers.
throwstatements should only throw anErrorinstance.- Object properties should be destructured, rather than assigned to variables via direct access.
- Use
<Array>.find()instead of<Array>.filter()[0]to find an element in an array. - Use
<Array>.includes()instead of<Array>.indexOf() === -1. - Use
??instead of||. - Use optional chaining when possible.
- Promises that reject should always return an Error.
- Class members that are not modified outside of the constructor should be
readonly. - The
.reduce()callback should have typed parameters. - When using a non-global regular expression, use
<RegExp>.execover<String>.match(). - Class methods that return
thisshould havethisas the return type, not the class. - When testing the beginning or end of a string, use
<String>.startsWith()or<String>.endsWith(). - Functions which return a Promise must use the
asynckeyword. <Array>.sort()should always be given a compare function.asyncfunctions must useawait, or be rewritten without the promise.- The
+operator can only be used with operands of the same type. - Values interpolated in a template string must be of type
string. - Functions which return a promise should await that return value.
- Conditions should not use nullable values - you must always explicitly compare against
nullorundefined. - Switch statements are not preferred, but when you must use them it should have exhaustive cases.
- Unbound class methods must be called with the expected scope (e.g.
myClass.method.bind(myClass)). - The
errorparameter in a catch statement is of typeunknown. - Function overload signatures must be grouped together.
- Array type definitions should use the generic
Array<T>overT[]. @tsdirectives are disallowed, except for@ts-expect-errorwhich requires a description.- Classes with static public properties should have a getter for each property.
- Class methods which are not static must make use of
thisor be converted to static. - Prefer passing type arguments to a constructor instead of a type annotation.
- Prefer
Record<string, T>over{ [key: string]: T}. - Do not use any type assertions (
x as T). - Object types should be defined with
interfaceovertype. - Imported values which are only used as types should be imported with
type. - Function parameters which are optional or have a default value should come after all mandatory parameters.
- Functions should always have an explicit return type.
- All class members should have an accessibility modifier (
public,protected,private). - All exported functions and public class methods should have explicit parameter and return types.
- Variables should always be initialised with a value.
- Functions which take more than three arguments should take a single object instead.
- Class members should be ordered as
constructor,fields,statics,getters,setters, thenmethods. - Method types should use the property signature
func: (arg: string) => string. - Variables should use
camelCase, types and classes should usePascalCase. Only variables may use a leading underscore to indicate they are unused. - Never use the
Arrayconstructor. - Do not use non-null assertions.
- Enums should not have duplicate values.
- Do not use the
deleteoperator on dynamic property accesses. - Functions, interfaces, and object types should never be empty.
- Do not use
any. - Classes should not consist solely of static members.
- The
for...inloop should not be used. - When all imported members are type imports, use
import type { a, b }overimport { type a, type b }. - Do not use type annotations for variables with a string, number, or boolean value. These can be inferred.
- The
voidtype should only be used as the sole return type of a function.(): void | stringis invalid. - Do not reference unsafe values in a loop.
- Do not use number literals which would lose precision due to memory constraints.
- Classes should use
constructor(), notnew(). Interfaces for the class should usenew(), notconstructor(). - Do not use namespaces.
- Do not use
require(). - Do not declare variables in an inner scope that share a name with a variable in the outer scope.
- Do not alias
this. - Do not needlessly assign constructor parameters to class members of the same name.
- Do not
extendsanyorunknown. - Unused expressions should be removed.
- Unused variables should be removed.
- Do not access a variable before its definition.
- Do not define empty constructors.
- Do not define empty exports.
- Do not use wrapper types (e.g. use
boolean, notBoolean). - Use
as constover literal types. - Enum values should always be explicitly initialised.
- The
for...ofloop should be used over theforloop, when the index value is not needed. - Enum values should always be literal values.
- Do not use TypeScript’s
///reference. - Do not use overloads when the same result can be achieved via union types or optional parameters.
3.1.3. ESLint-Comments Enforced Rules
Section titled “3.1.3. ESLint-Comments Enforced Rules”- Do not use blanket
eslint-disabledirectives. Alldisabledirectives must target specific rules. - All
disabledirectives must include a comment explaining why the linter is being bypassed.
3.1.4. Deprecation Enforced Rules
Section titled “3.1.4. Deprecation Enforced Rules”- Do not use deprecated methods/features, even if the package still supports them.
3.1.5. Import Enforced Rules
Section titled “3.1.5. Import Enforced Rules”- Do not use default imports if the module does not have a default export.
- Do not import modules simply to re-export them.
- Exports should always be at the end of the file.
- With the exception of packages, imports should always have a file extension.
- Imports should always be at the beginning of the file.
- If a module has multiple named exports, group them in a single
export { a, b }declaration. - Import statements should be followed by a newline.
- Import paths should never be absolute
- You should not use AMD syntax
- You should not use CJS syntax
- You should not define cyclical imports (if file a imports file b, file b CANNOT import file a)
- Modules should not use a default export.
- A module should not import the same file multiple times.
- You should not use dynamic
requirecalls. - Named import blocks cannot be empty.
- You should not import packages that are not included in the
package.jsonfile. - You cannot
importa CommonJS module. - Exports must always be declared with
const. - You cannot use a named export as the default export.
- You cannot use a named export as the property of a default export.
- You should not have orphaned modules (modules without any exports, or a module which is never imported).
- You cannot use webpack loader syntax.
- Imports must be sorted alphabetically, first grouped by: builtin node modules, external packages, internal packages, modules in parent directory, modules in current directory, type-only imports.
- There should be no new lines between these groups.
3.1.6. JSDoc Enforced Rules
Section titled “3.1.6. JSDoc Enforced Rules”@accesstags should be one ofpackage,private,protected, orpublic.- Asterisks should be aligned.
- Lines should not be improperly indented.
@paramnames should reflect the actual parameters.@propertynames should reflect the actual properties.- Should not use
=(GCC syntax). - All tags must be valid JSDoc tags.
@templatenames should be used in the@typedef.@licensetag MUST be set toNaomi's Public License, which is the spelling the ESLint configuration requires.- Tags that do not expect content should not have content.
@implementsshould only be used on constructors or classes.- Tag descriptions should not be just a reflection of the name.
- Description tags must be complete sentences.
- JSDocs must be multiple lines. The first and last line cannot have text content.
- JSDoc syntax must be valid.
- JSDocs must have a description.
- JSDocs cannot be empty.
- A hyphen should separate the parameter name from the description.
- JSDocs are required on all public functions, classes, and methods. They are encouraged on all public exports.
- Parameters must have a name and description.
- Properties must have a name and description.
- If a function returns a value, it must be documented in
@returns. - If a function throws an unhandled error intentionally, it must be documented in
@throws. - If a generator yields a value, it must be documented in
@yields. - Tags must be sorted alphabetically.
- There should be no blank lines between tags.
- Any types referenced must be valid types.
3.1.7. Unicorn Enforced Rules
Section titled “3.1.7. Unicorn Enforced Rules”- Regular expressions should use special shorthand where possible.
catchblocks should always haveerroras the parameter.- When destructuring an object, all consumed properties should be destructured. Do not perform direct property access on an object that is previously destructured.
- When spreading a ternary in an array, both sides of the expression must be of the same type.
- Functions should be declared in the highest scope possible.
Error()constructor calls must always be given a message.- Escape sequences must use uppercase text.
- Files should be named in camelCase.
- Do not pass function references as callbacks to array methods.
- Do not use
.forEach(). - Do not use
thisin array methods. - Do not chain
.push()calls. - Do not use
.reduce(). - Do not access properties directly from an
awaitexpression. - Do not use
awaitin Promise methods such as.all(). - Files should not be empty.
- Do not use a
forloop when you can use afor...ofloop. - Use Unicode escape sequences over hexadecimal escape sequences.
- Use
Array.isArray()overinstanceof Array. GETorHEADrequests should never have a body.- Do not declare variables that start with
neworclass. - Do not use
.lengthas the argument to.slice(). - Use
Buffer.from(), notnew Buffer(). - Do not use objects as default parameters.
- Do not pass single-element arrays to Promise methods.
- Do not define a class that only has static members.
- Do not use
.then(). - Do not assign to
this. - Do not use
typeof x === "undefined". awaitcannot be used on non-promise values.- You cannot ignore consecutive values when destructuring an array, e.g.
[,,,, val]. - You cannot use IIFEs.
- Promises should not return
.resolve()or.reject(). - You should not spread an array into a new array without adding values.
- You should not associate any case statements with the default statement.
- Number literals cannot have trailing zeroes after the decimal place.
- Number literals must use proper case.
- Numbers over 9999 should use
_to separate each group of three digits, e.g.10_000. - If you need to flatten an array, use
Array.flat(). - Prefer
.flatMap()over.map().flat(). - Prefer
indexOfoverfindIndex. - Prefer
.some()over.filter().length. - Prefer
.at()for accessing array and string indices. - Prefer
.codePointAt()over.charCodeAt(). - Prefer
Date.now()overnew Date().getTime(). - Use default parameters instead of reassigning undefined values.
- Use
Math.truncto round numbers, not bitwise operators. - Use ESM modules, not CJS.
- Use coercion functions such as
String()directly. - Use a negative index instead of
.length - 1. - Use the
node:protocol when importing built-in packages. - Use
Numberproperties instead of global helpers e.g.Number.isNaN()overisNaN(). - Use
Object.fromEntriesto create an object from key-value pairs. - If a
catchblock does not use theerrorparameter, the parameter should be omitted. - Prefer calling prototype methods over instance methods.
- Prefer using
Set.has()overArray.includesto check for existence. - Prefer using
Set.sizeoverArray.length. - Prefer using the spread operator over
Array.concat()orString.split(""). - Prefer using
String.replaceAll()over regex searches. - Prefer
String.slice()overString.substr[ing](). - Prefer
String.startsWith()or.endsWith()overRegExp.test(). - Prefer
String.trim[Start|End]()overString.trim[Left|Right](). - Use
structuredCloneto create a deep clone of an object. - Use top-level await instead of IIFEs.
- Variable names should not be abbreviated.
Array.join()must always be given a separator.Number.toFixed()must always be given a digits argument.
3.2. React Rules
Section titled “3.2. React Rules”These rules apply to TSX, and will run on files in src/**/*.tsx.
- Boolean properties should be named accordingly, such as
isEnabledinstead ofenabled. - Buttons must always have a
typeattribute. - If a radio button or checkbox is checked, it must be
readonlyor have anonChangehandler. - Default properties should match the property types.
- Properties, state, and context should always be destructured.
- Components must always have a name.
- A component cannot consume another component’s propTypes.
- PropTypes cannot use
any,array, orobject. forwardRefcomponents must useref.- Components should always be defined as named arrow functions.
- State should have matching names, e.g.
[color, setColor]. iframesshould always use thesandboxattribute.- Boolean properties should always be explicitly written:
<Component prop={true}>. - Spaces between JSX elements must be explicitly written:
{' '}. - Files that contain JSX must have the extension
.jsxor.tsx. - Fragments should always use the shorthand syntax.
- Event handlers must be appropriately named:
onChange={this.handleChange} - Iterators must always have a
keyprop, and it should never be the index. - You should not use
.bind()in component props - You should not insert comments as text nodes.
- Contexts should not use mutable values (e.g. objects), to prevent re-renders.
- Components should not have duplicate properties.
- Avoid leaking conditional values. Prefer
condition ? <Component> : nullovercondition && <Component>. - Element text should always be wrapped in JSX containers.
- You should never use
javascript:urls. target=_blankmust always be accompanied withrel=noreferrer.- You should not use variables that are not declared.
- You should not use fragments unless there is no singular wrapping element.
- Components should use PascalCase.
- You should not spread props multiple times.
- Props should be sorted alphabetically.
- You should not access
this.stateinside anysetStatefunctions. - You should not use arrow functions for lifecycle methods.
- Children cannot be passed as props.
- You cannot use dangerous properties (
dangerouslySetInnerHTML). - You cannot use deprecated methods.
- You cannot use
setStateincomponentDidMountorcomponentDidUpdateorcomponentWillUpdate. - You cannot directly mutate
this.state. - You cannot use
findDOMNode. - You cannot use
isMounted. - Each file should have only one component.
ReactDOM.render’s return value should not be used.- You should not use string references.
thiscannot be used in stateless functional components.- HTML entities must be escaped.
- You cannot use unknown HTML properties.
- You cannot use unsafe lifecycle methods.
- You cannot define a component within another component.
- Class components should not have unused methods.
- Components should not have unused propTypes or state
- Class components should use the ES6
class Component extends React.Componentsyntax. - Props should be readonly.
- Stateless components should be pure functions.
- Property accesses must be reflected in the propTypes.
- Any optional property must have a default value.
- Classes using the
rendermethod MUST return a value. - Components without children must still have a separate closing tag.
- State initialisation must always happen in the constructor.
- Static properties should be defined as
static name =. - The
styleproperty must always be an object. - Void elements
img,bretc. must never have children.
3.3. Playwright Rules
Section titled “3.3. Playwright Rules”These files apply to Playwright End-to-end tests, and will run on e2e/**/*.spec.ts.
- All tests must have at least one
expectassertion. describecalls cannot be nested more than two levels deep.- Playwright APIs must be
awaited. - Tests cannot be commented out.
expectcannot be called conditionally.- Tests cannot contain conditional logic.
- Setup and teardown hooks cannot be duplicated.
- You cannot use element handles (
page.$). - You cannot use
page.$eval(). - Tests cannot be focused with
.only(). - Tests cannot be forced with
{ force: true }. - You cannot use
getByTitle(). - You cannot use the
networkidleoption. - You cannot use
first(),last(), ornth(). - You cannot use
page.pause(). - You cannot use
page.locator(). Prefer specific methods likepage.getByRole(). - Tests cannot be skipped with
.skip(). expectcan only be called within test blocks.- You cannot reference variables in
page.evaluate(). - Some Playwright methods are synchronous - these cannot be
awaited. - You cannot use
.not()when a specific matcher exists. - You cannot use
page.waitForSelector()orpage.waitForTimeout(). - Prefer
.toBeGreaterThan()over(x > 5).toBe(true). - Prefer
.toBe(5)over(x === 5).toBe(true) - Hooks should be ordered as Playwright calls them:
beforeAll,beforeEach,afterEach,afterAll. - Hooks should be at the top of the test.
- Test names should be lowercase.
- Use
.toStrictEqual()over.toEqual(). - Use
.toBe()over.toStrictEqual()for primitive values. - Use
.toContain()over.includes(). - Use
.toHaveCount()overlocator.count()and.toHaveLength()over.length. - Prefer assertions like
.toBeVisible()over(locator.isVisible()).toBe(true). - Setup and teardown code must be in a hook.
.toThrow()assertions require a message.- Tests must be within a
describeblock. - All
expect()calls must have a custom message. - Promises that contain an
expectmust be awaited. - Tests must have a title that is not empty.
3.4. Vitest Rules
Section titled “3.4. Vitest Rules”These files apply to Vitest unit tests, and will run on test/**/*.spec.ts.
- Files must have
.spec.tsextension. - consistent-test-it
- Tests must have at least one
expect. describecalls cannot be nested more than two levels deep.- Prefer
.toHaveBeenCalled()over.toBeCalled(). - Tests cannot be commented out.
expectcannot be called conditionally.- Tests cannot contain conditional logic.
- Tests cannot be run conditionally.
- Tests cannot be disabled.
- You cannot use the
done()callback. - Setup and teardown hooks cannot be duplicated.
- Tests cannot be focused with
.only(). - Test titles must be unique.
node:testcannot be imported.- Snapshots cannot use string interpolation.
expectmust be withinitortest.- Tests cannot use
return. - Prefer
toHaveBeenCalledWith()overtoHaveBeenCalled(). - Prefer
.toBeGreaterThan()over(x > 5).toBe(true). - Use
describe.eachinstead of manual loops. - Prefer
.toBe(5)over(x === 5).toBe(true). - All tests must start with
expect.assertions(number). - Use
expect.resolves(fn)overexpect(await fn). - Hooks should be ordered as Vitest calls them:
beforeAll,beforeEach,afterEach,afterAll. - Hooks should be at the top of the test.
- Test titles should be lowercase.
- Prefer
vi.fn().mockResolvedValue(val)overvi.fn().mockImplementation(() => Promise.resolve(val)). - Prefer
vi.spyOn(Date, "now")instead of overwriting the globalDate.now = vi.fn(). - Use
.toStrictEqual()over.toEqual(). - Use
.toBe()over.toStrictEqual()for primitive values. - Use
.toBeFalsy()over.toBe(false). - Use
.toBeObject()over.toBeInstanceOf(Object). - Use
.toBeTruthy()over.toBe(true). - Use
.toContain()over.includes(). - Use
.toHaveLength()over.length. - Use
test.todo()instead oftest.skip(). - Setup and teardown code must be in a hook.
.toThrow()assertions require a message.- Tests must be within a
describeblock. - The
describecallback should not have any parameters and cannot usereturn. - All
expect()calls must have a custom message. - Tests must have a title that is not empty.
4. LIMITATION OF LIABILITY AND DISCLAIMERS
Section titled “4. LIMITATION OF LIABILITY AND DISCLAIMERS”4.1. Reference to Comprehensive Liability Framework
Section titled “4.1. Reference to Comprehensive Liability Framework”IMPORTANT: Comprehensive liability limitations, damage exclusions, and maximum liability caps are set forth in our Limitation of Liability and Indemnification Policy, which is incorporated herein by reference.
4.2. Style Guide Disclaimer
Section titled “4.2. Style Guide Disclaimer”This Guide establishes mandatory standards for code contributions. However, compliance with this Guide does not guarantee acceptance of contributions. Project maintainers reserve the right to:
- Request modifications to code that complies with this Guide
- Reject contributions for reasons beyond style compliance
- Modify or update this Guide at any time without prior notice
- Interpret Guide requirements in specific contexts as necessary
4.3. Technical Accuracy Disclaimer
Section titled “4.3. Technical Accuracy Disclaimer”While we strive to maintain accurate and current information in this Guide, technical standards, tooling, and best practices evolve continuously. Contributors are responsible for:
- Verifying current tool versions and compatibility
- Ensuring their development environment matches project requirements
- Adapting to updates in this Guide as they are published
- Consulting project-specific documentation for additional requirements
5. CONCLUSION
Section titled “5. CONCLUSION”This Style Guide represents our commitment to maintaining high-quality, consistent, and maintainable code across all projects. By adhering to these standards, contributors help ensure that our codebase remains accessible, professional, and aligned with industry best practices.
All contributors are expected to familiarise themselves with and comply with the requirements set forth in this Guide. Questions about specific requirements or requests for clarification should be directed to project maintainers through appropriate communication channels.
For questions about style requirements or to suggest improvements, please contact project maintainers through the designated channels outlined in our Contributor Covenant.