From onenote-pack
Sets up GitHub Actions CI pipelines for OneNote Graph API integrations using MSW mocks or live Azure AD tests with credential isolation.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin onenote-packThis skill is limited to using the following tools:
Testing OneNote integrations in CI requires Azure AD app registration, credential management, and mock strategies for Graph API responses. This skill provides two proven CI strategies: mock-only PR checks (zero Azure credentials required) and nightly live integration tests with proper credential isolation and rate limit awareness.
Sets up local dev loop for OneNote Graph API integrations with MSW mock responses and fixtures. Avoids Azure auth and rate limits; switchable to live mode via GRAPH_MODE.
Configures GitHub Actions CI/CD pipelines for Evernote integrations with JS mock NoteStore for unit tests and sandbox integration tests.
Provides Azure DevOps YAML pipeline best practices on multi-stage structures, triggers, scheduling, variables, caching, templates, and security for efficient CI/CD.
Share bugs, ideas, or general feedback.
Testing OneNote integrations in CI requires Azure AD app registration, credential management, and mock strategies for Graph API responses. This skill provides two proven CI strategies: mock-only PR checks (zero Azure credentials required) and nightly live integration tests with proper credential isolation and rate limit awareness.
Use msw (Mock Service Worker) to intercept Graph API calls with zero Azure dependency:
// tests/mocks/handlers.ts
import { http, HttpResponse } from "msw";
const GRAPH = "https://graph.microsoft.com/v1.0";
export const handlers = [
http.get(`${GRAPH}/me/onenote/notebooks`, () =>
HttpResponse.json({ value: [
{ id: "nb-001", displayName: "Work Notes", createdDateTime: "2026-01-15T10:00:00Z" },
]})),
http.get(`${GRAPH}/me/onenote/sections/:sectionId/pages`, () =>
HttpResponse.json({ value: [
{ id: "page-001", title: "Sprint Review", createdDateTime: "2026-03-10T14:00:00Z" },
]})),
http.post(`${GRAPH}/me/onenote/sections/:sectionId/pages`, async ({ request }) => {
const body = await request.text();
if (!body.includes("<html")) {
return new HttpResponse(JSON.stringify({
error: { code: "InvalidArgument", message: "Page content must be valid XHTML" }
}), { status: 400 });
}
return HttpResponse.json({ id: "page-new", title: "Created Page" }, { status: 201 });
}),
];
// tests/setup.ts
import { setupServer } from "msw/node";
import { handlers } from "./mocks/handlers";
export const server = setupServer(...handlers);
beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
Required GitHub Secrets: AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET.
Warning: ClientSecretCredential (app-only auth) was deprecated March 31, 2025 for OneNote APIs. CI test environments may still use it for automation, but production code must use delegated auth. Monitor Microsoft deprecation notices.
# .github/workflows/onenote-pr.yml — Mock-only, every PR
name: OneNote PR Checks
on: [push, pull_request]
jobs:
mock-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: npm }
- run: npm ci && npm test -- --reporter=verbose
env: { ONENOTE_TEST_MODE: mock }
# .github/workflows/onenote-nightly.yml — Live tests, daily 3AM UTC
name: OneNote Integration Tests
on:
schedule: [{ cron: "0 3 * * *" }]
workflow_dispatch:
jobs:
integration:
runs-on: ubuntu-latest
concurrency: { group: onenote-live-tests, cancel-in-progress: false }
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: npm }
- run: npm ci && npm test -- --testPathPattern="integration"
env:
ONENOTE_TEST_MODE: live
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
- name: Cleanup test notebooks
if: always()
run: node scripts/cleanup-test-notebooks.js
env:
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
Each test creates resources with a unique prefix. Note: OneNote notebooks cannot be deleted via Graph API — use a disposable test tenant or archive-based cleanup.
// tests/helpers/test-context.ts
import { randomUUID } from "crypto";
export function createTestContext() {
const prefix = `ci-test-${randomUUID().slice(0, 8)}`;
return {
notebookName: `${prefix}-notebook`,
sectionName: `${prefix}-section`,
prefix,
};
}
Stay under 600 req/60s per user across parallel test jobs:
export async function withRateLimit<T>(fn: () => Promise<T>): Promise<T> {
await new Promise((r) => setTimeout(r, 200));
try { return await fn(); }
catch (err: any) {
if (err?.statusCode === 429) {
const retry = parseInt(err.headers?.["retry-after"] ?? "5", 10);
await new Promise((r) => setTimeout(r, retry * 1000));
return fn();
}
throw err;
}
}
.github/workflows/onenote-pr.yml — mock-based PR check workflow.github/workflows/onenote-nightly.yml — live integration test workflowtests/mocks/handlers.ts — MSW handlers for Graph API endpointstests/setup.ts — mock server lifecycle managementtests/helpers/test-context.ts — test isolation with unique prefixes| CI Error | Cause | Fix |
|---|---|---|
401 Unauthorized in nightly | Expired client secret | Rotate AZURE_CLIENT_SECRET in GitHub Settings > Secrets |
403 Forbidden in live tests | Missing Notes.ReadWrite scope | Update app registration API permissions in Azure portal |
| Mock handler mismatch | onUnhandledRequest: "error" caught unknown URL | Add missing endpoint to handlers.ts |
| Rate limit in parallel jobs | Multiple CI runs hitting same tenant | Use concurrency group to serialize nightly runs |
| Orphaned test notebooks | Cleanup step skipped | OneNote notebooks cannot be API-deleted; archive manually |
# Run mock tests locally
ONENOTE_TEST_MODE=mock npm test
# Run single integration test against live API
ONENOTE_TEST_MODE=live AZURE_TENANT_ID=xxx AZURE_CLIENT_ID=yyy \
AZURE_CLIENT_SECRET=zzz npx vitest run tests/integration/notebooks.test.ts
onenote-deploy-integrationonenote-debug-bundleonenote-rate-limits