Skip to content

Commit

Permalink
Test style guidance (#1957)
Browse files Browse the repository at this point in the history
* Create test-style-guide.md

* Create tests.code-snippets

* Update test-style-guide.md
  • Loading branch information
cspotcode authored Feb 13, 2023
1 parent ba741fa commit 1c5857c
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 0 deletions.
66 changes: 66 additions & 0 deletions .vscode/tests.code-snippets
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"Test: macro": {
"prefix": "macro",
"body": [
"const macro = test.macro(($1) => async (t) => {",
" $0",
"});"
]
},
"Test: macro w/title": {
"prefix": "macroTitle",
"body": [
"const macro = test.macro(($1) => [",
" (given) => given,",
" async (t) => {",
" $0",
" }",
"]);"
]
},
"Test: suite": {
"prefix": "suite",
"body": [
"test.suite(\"$1\", (${2|test,{context},{contextEach}|}) => {",
" ${2/(test$)|(\\{context\\}$)|(\\{contextEach\\}$)/${2:+const test = context(}${3:+const test = contextEach(}/m}$0",
"});"
]
},
"Test: context builder": {
"prefix": "ctx",
"body": [
"export const ctx${1:Name} = async (t) => {",
" $0",
" return {};",
"};",
"export namespace ctx$1 {",
" export type Ctx = Awaited<ReturnType<typeof ctx$1>>;",
" export type T = ExecutionContext<Ctx>;",
"}"
]
},
"Test: before": {
"prefix": "before",
"body": [
"test.before(async (t) => {",
" $0",
"});"
]
},
"Test: beforeEach": {
"prefix": "beforeEach",
"body": [
"test.beforeEach(async (t) => {",
" $0",
"});"
]
},
"Test: teardown": {
"prefix": "teardown",
"body": [
"t.teardown(async (t) => {",
" $0",
"});"
]
}
}
33 changes: 33 additions & 0 deletions development-docs/test-style-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
## Test guidelines

*These notes are my attempt at keeping myself consistent when writing tests. Nothing too formal.*

### DRYing up tests with reusable functions

If a reusable function does not need access to anything from the context,
it's a plain function.

If the reusable function needs access to stuff from context, it's a
context helper.

If the reusable function implements all the necessary assertions within itself, it's a macro.

### Function args

Plain functions w/many options should accept a single option-bag.
Should also have `setOptions` method to overlay additional options, and `getOptions` to inspect.
*At time of writing, I have not implemented `setOptions` nor `getOptions`*

Never destructure `t`
Never destructure `test`
Only exception: destructure `{context}` or `{contextEach}` if calling `const test = context(fooCtx)` b/c avoids `test = _test.context()`

### Consistent naming

When exec-ing a process:

Awaited result is in local var `r`
Non-awaited is in local var `p`
Do not destructure either way.

Context builders are named with a `ctx` prefix and also declare a couple types on their namespace. See src/test/helpers/ctx* for format.

0 comments on commit 1c5857c

Please sign in to comment.