mirror of
https://github.com/alirezarezvani/claude-skills.git
synced 2026-10-07 02:58:13 +00:00
Same root cause as #587/#591 — Claude Code's runtime loader rejects array-form skills paths like ["./content-production", "./ai-seo", ...] even when each entry is a valid subdirectory containing SKILL.md. `claude plugin validate` accepts them but the loader does not. The proven canonical layout (used by self-improving-agent in #536): <plugin>/ ├── .claude-plugin/plugin.json skills: "./skills" └── skills/ ├── <skill-1>/SKILL.md ├── <skill-2>/SKILL.md └── ... Restructured 9 multi-skill domain plugins: - business-growth (4 skills moved) - c-level-advisor (28) - engineering (36) - engineering-team (32) - finance (2) - marketing-skill (43) - product-team (12) - project-management (8) - ra-qm-team (13) Also fixed standalone plugins that had root SKILL.md + ./skills/ subdir (agenthub, autoresearch-agent, executive-mentor, playwright-pro). The loader rejected them despite skills="./skills" because of the conflicting root SKILL.md (compare self-improving-agent which works because PR #536 moved its root SKILL.md). Moved each root SKILL.md into ./skills/<name>/. Restored standalone plugin folders to their original paths after the multi-skill restructure swept them into parent skills/ directories (marketplace.json source paths require original locations). Removed 7 orphaned marketplace entries that pointed to skill folders without their own plugin.json (content-creator, demand-gen, fullstack-engineer, aws-architect, product-manager, scrum-master, skill-security-auditor) — these were already non-functional. Bumped patch versions on every changed plugin and synced marketplace.json. Marketplace now lists 29 working plugins (down from 36). After merge: users run `/plugin marketplace update claude-code-skills` followed by `/plugin update --all` to pick up the working layout.
2.2 KiB
2.2 KiB
Assertions Reference
Web-First Assertions (Always Use These)
Auto-retry until timeout. Safe for dynamic content.
// Visibility
await expect(locator).toBeVisible();
await expect(locator).not.toBeVisible();
await expect(locator).toBeHidden();
// Text
await expect(locator).toHaveText('exact text');
await expect(locator).toHaveText(/partial/i);
await expect(locator).toContainText('partial');
// Value (inputs)
await expect(locator).toHaveValue('entered text');
await expect(locator).toHaveValues(['option1', 'option2']);
// Attributes
await expect(locator).toHaveAttribute('href', '/dashboard');
await expect(locator).toHaveClass(/active/);
await expect(locator).toHaveId('main-nav');
// State
await expect(locator).toBeEnabled();
await expect(locator).toBeDisabled();
await expect(locator).toBeChecked();
await expect(locator).toBeEditable();
await expect(locator).toBeFocused();
await expect(locator).toBeAttached();
// Count
await expect(locator).toHaveCount(5);
await expect(locator).toHaveCount(0); // element doesn't exist
// CSS
await expect(locator).toHaveCSS('color', 'rgb(255, 0, 0)');
// Screenshots
await expect(locator).toHaveScreenshot('button.png');
await expect(page).toHaveScreenshot('full-page.png');
Page Assertions
await expect(page).toHaveURL('/dashboard');
await expect(page).toHaveURL(/\/dashboard/);
await expect(page).toHaveTitle('Dashboard - App');
await expect(page).toHaveTitle(/Dashboard/);
Anti-Patterns (Never Do This)
// BAD — no auto-retry
const text = await locator.textContent();
expect(text).toBe('Hello');
// BAD — snapshot in time, not reactive
const isVisible = await locator.isVisible();
expect(isVisible).toBe(true);
// BAD — evaluating in page context
const value = await page.evaluate(() =>
document.querySelector('input')?.value
);
expect(value).toBe('test');
Custom Timeout
// Override timeout for slow operations
await expect(locator).toBeVisible({ timeout: 30_000 });
Soft Assertions
Continue test even if assertion fails (report all failures at end):
await expect.soft(locator).toHaveText('Expected');
await expect.soft(page).toHaveURL('/next');
// Test continues even if above fail