Skip to content
Draft
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4428f0b
Initial concept
fflaten Jul 19, 2026
2563bc5
Update mobile design
fflaten Jul 19, 2026
98f1f3c
Make modules list clickable links in tracker
fflaten Jul 19, 2026
af128b2
Refactor to be dynamic and easier to maintain
fflaten Jul 19, 2026
ad0d0b9
Add support for diff-highlighting in codeblocks
fflaten Jul 19, 2026
b88e51d
Fix dark mode contrast issues
fflaten Jul 19, 2026
5c1c40c
Add tutorial link to quick start
fflaten Jul 19, 2026
51813d6
Add first draft of remaining modules
fflaten Jul 19, 2026
803c455
Minor adjustments
fflaten Jul 20, 2026
8ecebed
Hide version dropdown in navbar when not relevant
fflaten Jul 20, 2026
d95a6ae
Trigger CI
fflaten Jul 20, 2026
bf6bc23
Minor update to trigger CI
fflaten Jul 20, 2026
2fb6c44
Split Commands to own sidebar and use a root category in each sidebar…
fflaten Jul 20, 2026
e8091d2
Underline active navbar link (sidebar)
fflaten Jul 20, 2026
77b3966
Adjust title on tracker
fflaten Jul 22, 2026
9ab6209
Adjust styling
fflaten Jul 22, 2026
bcdc3db
Update sidebars in v4 and v5
fflaten Jul 22, 2026
ba09237
Respect user-preferred version for links on index
fflaten Jul 22, 2026
e4b2419
Update tutorial and add module for test organisation
fflaten Jul 22, 2026
3ca1a4c
Fix broken coverage docs for using ExcludeFromCodeCoverage
fflaten Jul 22, 2026
a98f10b
Content updates
fflaten Jul 22, 2026
da84c57
Apply suggestions from code review
fflaten Jul 25, 2026
0b9d254
Apply suggestions from code review
fflaten Jul 25, 2026
172e2e2
Fix stuck hover effect on mobile
fflaten Jul 25, 2026
46df5f6
Minor adjustments
fflaten Jul 25, 2026
1d9a516
Cleanup config
fflaten Jul 25, 2026
092264e
Revert "Fix stuck hover effect on mobile"
fflaten Jul 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/quick-start.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ description: Get started using Pester to test your PowerShell scripts, functions

> **tl;dr:** Here is a [summary.](#summary)

:::tip Prefer to learn by building?
This page is the fast tour. If you would rather work through a single worked example from an empty folder to a tested module running in CI, start the [follow-along tutorial](/tutorial/introduction/welcome) instead.
:::

## What is Pester?

Pester is a testing and mocking framework for PowerShell.
Expand Down
21 changes: 18 additions & 3 deletions docs/usage/code-coverage.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -135,16 +135,31 @@ and there is an unreachable line of code in `FunctionTwo`.

### Excluding functions from coverage

To exclude a function (or scriptblock) from code coverage. Place `[ExcludeFromCodeCoverageAttribute()]` before the param block of the function:
To exclude a function (or scriptblock) from code coverage,
place `[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage()]` before the param block of the function:

```powershell
function FunctionExcluded {
[ExcludeFromCodeCoverageAttribute()]
function FunctionExcluded {
[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage()]
param()
"I am not included"
}
```

:::tip Using namespace
By placing a `using namespace` statement at the very top of your file, you can use a shorter name for the attribute.

```powershell
using namespace System.Diagnostics.CodeAnalysis

function FunctionExcluded {
[ExcludeFromCodeCoverage()]
param()
"I am not included"
}
```
:::

## Coverage Format

By default, Pester generates a `coverage.xml` file in [JaCoCo](https://www.jacoco.org/) format. It's read by most CI systems and coverage tools, so the default is a good choice for most projects. Pester v6 can also output [Cobertura](https://cobertura.github.io/cobertura/) format if you need it. You can change the output format, path, and encoding with the following options:
Expand Down
56 changes: 55 additions & 1 deletion docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,21 @@ const config = {
type: 'doc',
label: 'Docs',
docId: 'quick-start',
sidebarId: 'docs',
position: 'right'
},
{
type: 'doc',
label: 'Commands',
docId: 'commands/Add-ShouldOperator',
sidebarId: 'commands',
position: 'right'
},
{
type: 'docSidebar',
label: 'Tutorial',
docsPluginId: 'tutorial',
sidebarId: 'tutorial',
position: 'right'
},
{
Expand All @@ -74,7 +83,28 @@ const config = {
'bash',
'powershell',
'yaml'
]
],
// Declaring magicComments replaces the defaults, so the built-in highlight directives
// are repeated here. The diff directives mark lines added or removed relative to the
// previous version of a snippet — used by the tutorial when it evolves a file.
// Styling lives in src/css/custom.css.
magicComments: [
{
className: 'theme-code-block-highlighted-line',
line: 'highlight-next-line',
block: { start: 'highlight-start', end: 'highlight-end' },
},
{
className: 'code-block-diff-add-line',
line: 'diff-add',
block: { start: 'diff-add-start', end: 'diff-add-end' },
},
{
className: 'code-block-diff-remove-line',
line: 'diff-remove',
block: { start: 'diff-remove-start', end: 'diff-remove-end' },
},
],
},
// Please note that the Algolia DocSearch crawler only runs once every 24 hours.
// Configuration options below described at https://docusaurus.io/docs/search.
Expand Down Expand Up @@ -152,6 +182,30 @@ const config = {
copyright: `Copyright Pester Team © 2019-present`,
},
}),
plugins: [
[
'@docusaurus/plugin-content-docs',
/** @type {import('@docusaurus/plugin-content-docs').Options} */
({
// The follow-along tutorial lives in its own docs instance at /tutorial so it stays
// single-sourced. Content in /docs is copied verbatim into versioned_docs/ at every
// version cut, which would freeze and duplicate the tutorial per Pester version.

// "id" below MUST match TUTORIAL_PLUGIN_ID in src/tutorial/tutorialData.js.
// This is used to determine when to override the TableOfContents (TOC) with the combined tutorial tracker.
id: 'tutorial',
path: 'tutorial',
routeBasePath: 'tutorial',
sidebarPath: './sidebarsTutorial.js',
editUrl: 'https://github.com/pester/docs/edit/main',
// The progress tracker already shows the module, the page and where both sit in the
// tutorial, so breadcrumbs would only repeat it.
breadcrumbs: true,
// Do not set disableVersioning here. It throws for an instance with no versions file.
// Omitting it gives a single implicit version and no version dropdown, which is what we want.
}),
],
],
presets: [
[
'@docusaurus/preset-classic',
Expand Down
144 changes: 81 additions & 63 deletions sidebars.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* PlEASE NOTE:
* The API pages for pester-docs are generated using the
* NOTE:
* The Commands-pages for pester-docs are generated using the
* Alt3.Docusaurus.Powershell module. It takes the Get-Help
* information produced by the Pester module and uses it to
* 1) generate .mdx files with the required Docusaurus (markdown)
Expand All @@ -22,60 +17,83 @@

import commands from "./docs/commands/docusaurus.sidebar.js";

module.exports = {
docs: {
Introduction: [
"quick-start",
"introduction/installation",
],
Usage: [
"usage/file-placement-and-naming",
"usage/importing-tested-functions",
"usage/test-file-structure",
"usage/discovery-and-run",
"usage/parallel",
"usage/data-driven-tests",
"usage/setup-and-teardown",
"usage/tags",
"usage/skip",
"usage/mocking",
"usage/modules",
"usage/testdrive",
"usage/testregistry",
"usage/test-results",
"usage/code-coverage",
"usage/configuration",
"usage/output",
"usage/result-object",
"usage/vscode",
"usage/troubleshooting",
],
"Assertions": [
"assertions/should-command",
"assertions/should-beequivalent",
"assertions/soft-assertions",
"assertions/assertions",
"assertions/custom-assertions",
],
"Migration Guides": [
"migrations/v5-to-v6",
"migrations/v4-to-v5",
"migrations/breaking-changes-in-v5",
"migrations/v3-to-v4",
],
"Additional Resources": [
"additional-resources/articles",
"additional-resources/courses",
"additional-resources/misc",
"additional-resources/projects",
"additional-resources/videos",
],
"Contributing": [
"contributing/introduction",
"contributing/reporting-issues",
"contributing/feature-requests",
"contributing/pull-requests",
],
"Command Reference": commands
}
/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
const sidebars = {
docs: [
{
// Root category used to identify the root node in the breadcrumbs,
// can be removed once https://github.com/facebook/docusaurus/issues/6953 is fixed to avoid extra indent
type: 'category',
label: 'Documentation',
collapsible: false,
items: [
{
"Introduction": [
"quick-start",
"introduction/installation",
],
"Usage": [
"usage/file-placement-and-naming",
"usage/importing-tested-functions",
"usage/test-file-structure",
"usage/discovery-and-run",
"usage/parallel",
"usage/data-driven-tests",
"usage/setup-and-teardown",
"usage/tags",
"usage/skip",
"usage/mocking",
"usage/modules",
"usage/testdrive",
"usage/testregistry",
"usage/test-results",
"usage/code-coverage",
"usage/configuration",
"usage/output",
"usage/result-object",
"usage/vscode",
"usage/troubleshooting",
],
"Assertions": [
"assertions/should-command",
"assertions/should-beequivalent",
"assertions/soft-assertions",
"assertions/assertions",
"assertions/custom-assertions",
],
"Migration Guides": [
"migrations/v5-to-v6",
"migrations/v4-to-v5",
"migrations/breaking-changes-in-v5",
"migrations/v3-to-v4",
],
"Additional Resources": [
"additional-resources/articles",
"additional-resources/courses",
"additional-resources/misc",
"additional-resources/projects",
"additional-resources/videos",
],
"Contributing": [
"contributing/introduction",
"contributing/reporting-issues",
"contributing/feature-requests",
"contributing/pull-requests",
],
}
],
}
],
commands: [
{
// Root category used to identify the root node in the breadcrumbs,
// can be removed once https://github.com/facebook/docusaurus/issues/6953 is fixed to avoid extra indent
type: 'category',
label: 'Command Reference',
items: commands,
collapsible: false,
},
],
};

export default sidebars;
35 changes: 35 additions & 0 deletions sidebarsTutorial.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* Sidebar for the follow-along tutorial (docs plugin instance "tutorial", served at /tutorial).
*
* Fully autogenerated from the folder structure. Ordering comes from the number prefixes on
* folders and files (`2-testing-our-module/1-setup.mdx`), which Docusaurus strips from both
* the doc id and the URL — so the order lives next to the content and adding a page needs no
* edit here. Module labels come from each folder's _category_.json.
*
* The progress tracker reads this same generated sidebar at runtime, so it stays in sync
* automatically. See src/tutorial/useTutorialOutline.js.
*
* Note: do not give these categories a `link: {type: 'generated-index'}`. Generated index
* pages are not rendered through @theme/DocItem, so they would not show the tracker.
*/

/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
const sidebars = {
tutorial: [
{
// Root category used to identify the root node in the breadcrumbs,
// can be removed once https://github.com/facebook/docusaurus/issues/6953 is fixed to avoid extra indent
type: 'category',
label: 'Tutorial',
collapsible: false,
items: [
{
type: 'autogenerated',
dirName: '.',
}
],
},
],
};

export default sidebars;
62 changes: 62 additions & 0 deletions src/components/TutorialChecklist/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React, { useMemo } from 'react';
import clsx from 'clsx';
import { useDoc } from '@docusaurus/plugin-content-docs/client';
import { useTutorialProgress } from '@site/src/tutorial/TutorialProgressContext';
import styles from './styles.module.css';

/**
* End-of-page checklist. Checking every box marks the page complete in the tracker.
*
* Registered globally in src/theme/MDXComponents.js, so tutorial pages use it without an
* import:
*
* <TutorialChecklist items={[
* {id: 'create-module', label: 'I can scaffold a PowerShell module'},
* ]} />
*
* Item ids must be stable strings, never array indices — reordering the list must not
* transfer a checkmark from one statement to another.
*/
export default function TutorialChecklist({ items, title = 'Before you move on' }) {
const { metadata } = useDoc();
const { pages, setItemChecked } = useTutorialProgress();

const itemIds = useMemo(() => items.map((item) => item.id), [items]);
const state = pages[metadata.id]?.items ?? {};
const done = itemIds.filter((id) => state[id] === true).length;
const complete = itemIds.length > 0 && done === itemIds.length;

return (
<section className={clsx(styles.checklist, complete && styles.checklistComplete)}>
<div className={styles.header}>
<h2 className={styles.title}>{title}</h2>
<span className={styles.count}>
{done}/{itemIds.length}
</span>
</div>

<ul className={styles.items}>
{items.map((item) => {
const checked = state[item.id] === true;
return (
<li key={item.id}>
<label className={clsx(styles.item, checked && styles.itemChecked)}>
<input
type="checkbox"
className={styles.input}
checked={checked}
onChange={(event) =>
setItemChecked(metadata.id, item.id, event.target.checked, itemIds)
}
/>
<span>{item.label}</span>
</label>
</li>
);
})}
</ul>

{complete && <p className={styles.done}>Page complete. Your progress is saved in this browser.</p>}
</section>
);
}
Loading